Levantamos Dataset
Vamos a trabajar con un subconjunto de datos que surgió de un trabajo de limpieza y tratamiento de outliers que se puede consultar en el notebook de Preprocesamiento Dataset Properati, correspondiente a precios de propiedades en Capital Federal, cuyo precio está expresado en dolares (USD), el tipo de propiedad corresponde a Departamento, PH o Casa, y el tipo de operacion sea Venta.
datos_properati <- read.csv("properati_preprocesado.csv")
glimpse(datos_properati)
Rows: 49,835
Columns: 9
input string 2 is invalid in this localeinput string 17 is invalid in this localeinput string 20 is invalid in this localeinput string 25 is invalid in this localeinput string 40 is invalid in this locale
$ id [3m[38;5;246m<fct>[39m[23m AfdcsqUSelai1ofCAq2B0Q==, ESzybdH7YU2uIU1/kHtRGw==, r22OfzZ3kXooSPoE5HMuZQ==, atZQXVtyfG7+OiX6gYY3lA==, R…
$ l3 [3m[38;5;246m<fct>[39m[23m Velez Sarsfield, Nu<f1>ez, Almagro, Almagro, Almagro, Almagro, Almagro, Almagro, Almagro, Almagro, Almagr…
$ rooms [3m[38;5;246m<int>[39m[23m 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1, 1, 1, 4, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, …
$ bathrooms [3m[38;5;246m<int>[39m[23m 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, …
$ surface_total [3m[38;5;246m<int>[39m[23m 95, 44, 40, 49, 40, 40, 40, 49, 40, 23, 40, 40, 32, 40, 36, 90, 45, 54, 40, 33, 40, 40, 36, 38, 174, 32, …
$ surface_covered [3m[38;5;246m<int>[39m[23m 69, 38, 37, 44, 37, 37, 37, 44, 37, 23, 37, 37, 30, 34, 33, 90, 35, 48, 40, 32, 34, 36, 33, 34, 174, 29, …
$ price [3m[38;5;246m<dbl>[39m[23m 199900, 147000, 92294, 115000, 77000, 88900, 88798, 110975, 92943, 69000, 99000, 96984, 125000, 99500, 12…
$ property_type [3m[38;5;246m<fct>[39m[23m Casa, Departamento, Departamento, Departamento, Departamento, Departamento, Departamento, Departamento, D…
$ precio_en_miles [3m[38;5;246m<int>[39m[23m 200, 147, 92, 115, 77, 89, 89, 111, 93, 69, 99, 97, 125, 100, 122, 285, 150, 140, 110, 110, 96, 153, 108,…
La limpieza consistió en: eliminar la variable bedrooms por registrar gran presencia de faltantes (40%) y correlación positiva fuerte con la variable rooms (0.97), eliminar los registros con faltantes, descartar registros donde la superficie total resulta inferior a la cubierta, por tratarse probablemente de algún error de carga. Por último, se realizó un tratamiento de los outliers, empleando las técnicas vistas en la clase 3, quedando como resultado un dataset de 49.835 observaciones y 9 columnas, con el que trabajaremos a continuación.
Seleccionamos variables de interés
En este caso ya están preseleccionadas 9 variables:
- id: identificacion.
- l3: barrio.
- rooms: nro de habitaciones.
- bathrooms: nro de baños
- surface_total: superficie total en m2
- surface_covered: superficie cubierta en m2
- price: precio (variable a predecir) en dólares
- property_type: tipo de propiedad (Departamento, PH o Casa)
- precio_en_miles: variable creada por nosotros para graficar
datos_properati %>%
head()
Veamos cómo es la correlación entre las variables numéricas.
# graficamos con ggpairs coloreando por property type
g <- ggpairs(datos_properati %>% select(-c(id,l3)), aes(color = property_type),
upper = list(continuous = wrap("cor", size = 3, hjust=0.5)), legend = 25, progress=FALSE) +
theme(axis.text.x = element_text(angle = 90, hjust = 1), legend.position = "bottom") +
theme_bw()
# hacemos un loop para cambiar los colores del gráfico
for(i in 1:g$nrow) {
for(j in 1:g$ncol){
g[i,j] <- g[i,j] +
scale_fill_brewer(palette="Dark2") +
scale_color_brewer(palette="Dark2")
}
}
g
<<<<<<< HEAD

=======
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

>>>>>>> e6132d8d90ab69f2866605c879f144997998701b
- Las variables superficie cubierta y total presentan una asociación lineal positiva fuerte (0.945).
Respecto de nuestra variable a predecir, el precio, observamos que:
Existe una correlación positiva fuerte con las superficies total y cubierta. Respecto a estas últimas existe una gran diferencia en la correlación según el tipo de propiedad. Las casas parecen presentar menor correlación que los departamentos y PHs.
Existe una correlación positiva menor con el número de habitaciones y baños.
Modelo Múltiple
El modelo de regresión lineal múltiple es un modelo para la variable aleatoria Y cuando se conocen las variables regresoras. Es múltiple ya que vincula una serie de variables predictoras con Y.
El modelo en términos de las variables:
\[Y_i = β_0 + β_1X_{i1} + β_2X_{i2} + · · · + β_{p-1}X_{ip-1} + ε_i\] donde \(β_0\), \(β_1\),.., \(β_{p−1}\) son parámetros desconocidos, \(X_{i1}\), \(X_{i2}\), …, \(X_{ip-1}\) son los valores de las variables predictoras medidas en el i-ésimo individuo, \(Y_i\) es la variable respuesta medida en el i-ésimo individuo (observado) y \(ε_i\) es el error para el individuo i-ésimo (no observable).
Supuestos del modelo lineal
Se pueden resumir como \(ϵ_i\) ~ \(N(0,σ^2)\) para todo \(1<i<n\), independientes entre sí.
El modelo en términos de la esperanza condicional de Y dadas \(X_1\), \(X_2\),…, \(X_{p-1}\):
\[E(Y|X_1,X_2,...X_{p-1}) = β_0 + β_1X_{i1} + β_2X_{i2} + · · · + β_{p-1}X_{ip-1}\]
El modelo se denomina lineal puesto que la esperanza de Y condicional a las X’s depende linealmente de las covariables \(X_1\), \(X_2\),…, \(X_{p-1}\).
Estimación de los Parámetros (ajuste del modelo)
Se quiere ajustar un modelo para el precio de las propiedades en función de 2 variables:
\(precio = \beta_0 + \beta_1x_{i1} + \beta_2x_{i2} + \epsilon_i\)
Veamos cómo se interpretan los ajustes para los distintos tipos de predictores.
1) Predictores numéricos
Armemos un modelo para predecir el precio en función de la superficie cubierta y la cantidad de habitaciones. Veamos los resultados del modelo empleando la función tidy().
# ajustamos modelo lineal multiple
modelo_sc_r <- lm(price ~ surface_covered + rooms, data = train_data)
# Resumen del modelo
tidy_sc_r <- tidy(modelo_sc_r, conf.int = TRUE)
tidy_sc_r
<<<<<<< HEAD
=======
>>>>>>> e6132d8d90ab69f2866605c879f144997998701b
Significado de los coeficientes estimados
El valor de \(\hat{\beta_0}\) (ordenada al origen) es 21639 dólares, lo que corresponde al precio esperado de una propiedad con 0 habitaciones y sin superficie. Lo cual, este caso carecería de sentido ya que las propiedades deberían tener superficie y al menos alguna habitación/ambiente.
El coeficiente estimado de \(\hat{\beta_{surface\_covered}}\) (superficie cubierta) es de 3183 dólares, lo que indica que si mantenemos el número de habitaciones constante, cada incremento de un m2 adicional de superficie corresponde a un aumento de 3183 dólares, en promedio en el precio de la propiedad. O lo que es igual, dadas dos propiedades con la misma cantidad de habitaciones pero teniendo una un m2 más de superficie que la otra, el precio esperado para la de mayor superficie será 3183 dólares más alto que la de menor superficie.
¿Cómo se interpretaría el coeficiente estimado del número de habitaciones?
2) Predictores Categóricos
Armemos un modelo para predecir el precio de la propiedad en función de la superficie cubierta y el tipo de propiedad (property_type), que es categórica con tres niveles (Casa, Departamento o PH). Para ello, vamos a analizar primero el comportamiento de la variable que queremos predecir para cada tipo de propiedad a través de un boxplot.
# armamos boxplots paralelos de precio segun el tipo de propiedad (casa, dpto o ph)
ggplot(data = train_data, aes(y = precio_en_miles, group = property_type, fill = property_type)) +
geom_boxplot() +
scale_fill_brewer(palette="Dark2") +
theme_bw() +
theme(axis.text.x=element_blank(),
axis.ticks.x=element_blank()) +
labs(title = "Boxplots de precio según tipo de propiedad", subtitle = "En miles de dólares") +
labs(y = "Precio en miles de USD") +
labs(x = "Tipo de propiedad") +
facet_wrap(~property_type)

# Acotando la escala del grafico para visualizar mejor el rango intercuartil
ggplot(data = train_data, aes(y = precio_en_miles, group = property_type, fill = property_type)) +
geom_boxplot() +
scale_fill_brewer(palette="Dark2") +
theme_bw() +
scale_y_continuous(limits = c(0, 1000)) +
theme(axis.text.x=element_blank(),
axis.ticks.x=element_blank()) +
labs(title = "Boxplots de precio según tipo de propiedad", subtitle = "En miles de dólares") +
labs(y = "Precio en miles de USD") +
labs(x = "Tipo de propiedad") +
facet_wrap(~property_type)

Analizando la variable de tipo de propiedad en función de la variable a predecir, se observa una diferencia en los precios según el tipo de propiedad. En particular, las casas presentan mayores precios y a su vez, mayor variabilidad que los departamentos y PHs.
Veamos qué ocurre cuando ajustamos el modelo:
# ajustamos el modelo de superficie y tipo de propiedad
modelo_sc_pt <- lm(price ~ surface_covered + property_type, data = train_data)
tidy_sc_pt <- tidy(modelo_sc_pt, conf.int = TRUE)
tidy_sc_pt
Significado de los coeficientes estimados
¿Cómo cambia la interpretación de los coeficientes para la variable categórica?
El modelo de regresión lineal en este caso consiste simplemente en expresar la media del nivel de precios en cada población (de casas, departamentos o PHs) mediante tres coeficientes distintos, donde:
\(\beta_0\) (categoría basal de variable categórica) es la media del precio para las Casas sin superficie. En este modelo es de -2.1975210^{5} dólares, lo que carece de sentido económico ya que las casas deberían tener alguna superficie y no podrían tener un precio negativo.
\(\beta_0 + \beta_{property\_typeDepartamento}\) es la media del precio para los departamentos, dada la superficie. Por lo tanto, \(\beta_{property\_typeDepartamento}\) es la diferencia en los niveles medios de precios de los departamentos respecto de las casas (categoría basal).Es decir, \(\beta_{property\_typeDepartamento}\) (2.1871410^{5}) indica cuánto más alta es la función de respuesta (precio) para los departamentos respecto de las casas (categoría basal), dada la superficie.
Vemos que el nivel medio del precio es una función lineal de la superficie de la propiedad, con una misma pendiente \(\beta_{surface_total}\) 3310 para casas, departamentos y PHs.
¿Cómo se interpretaría entonces \(\beta_{property\_typePH}\)? ¿Y \(\beta_0 + \beta_{property\_typePH}\)?
Grafiquemos la regresión para las tres poblaciones
A continuación se muestra el gráfico de esta situación en que tenemos una variable categórica con tres niveles y una numérica. De la interpretación de coeficientes, se pudo ver que la regresión se puede expresar como rectas paralelas con igual pendiente pero distinto intercepto. Veamos cómo hacerla.
# Accedemos a la información de los coeficientes estimados
intercepto_C = modelo_sc_pt$coefficients[1] # β0
pendiente = modelo_sc_pt$coefficients[2] # β1
intercepto_D = modelo_sc_pt$coefficients[1] + modelo_sc_pt$coefficients[3] # β0 + β2
intercepto_PH = modelo_sc_pt$coefficients[1] + modelo_sc_pt$coefficients[4] # β0 + β3
# Graficamos el dataset y el modelo
train_data %>% ggplot(., aes(x = surface_covered, y = price)) +
geom_point() + #capa de los datos
geom_abline(intercept = intercepto_C, slope = pendiente, color = "forestgreen", size=1) + # capa del modelo
geom_abline(intercept = intercepto_D, slope = pendiente, color = "darkorange", size=1) + # capa del modelo
geom_abline(intercept = intercepto_PH, slope = pendiente, color = "slateblue3", size=1) + # capa del modelo
theme_bw() +
labs(title="Modelo Lineal Múltiple: Superficie y Tipo de Propiedad", x="Superficie en m2", y="Precio en miles de USD")

Predictores Cualitativos con muchas clases
La variable barrios (l3) tiene 57 niveles distintos. Veamos a través de boxplots paralelos cómo se comportan.
length(unique(datos_properati$l3)) # 57 barrios
[1] 57
# armo scatterplot de precios en miles en función de superficie total
ggplot( datos_properati, aes(x = fct_reorder(l3, price, .desc = T), y = price/1000)) +
geom_boxplot(alpha = 0.75, aes(fill = l3)) +
theme_minimal() +
theme(legend.position = 'none')+
labs(y = "Precios en miles", x = "Barrios") +
ggtitle("Boxplots de precios en función de los barrios")+
theme (axis.text.x = element_text(face="italic", colour="dark grey", size = 8, angle = 90))
(process:6086): Pango-WARNING **: 17:57:46.610: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.617: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.617: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.617: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.617: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.617: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.618: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.618: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.618: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.618: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.618: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.619: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.619: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.619: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.619: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.619: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.620: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.620: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.730: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.730: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.730: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.730: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.731: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.731: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.731: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.731: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.731: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.731: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.732: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.732: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.732: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.732: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.733: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.733: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.733: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.733: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.734: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.734: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.734: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.734: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.735: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.735: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.735: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.735: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.736: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.736: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.736: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.736: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.737: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.737: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.737: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.737: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.738: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.738: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.738: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.738: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.739: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.739: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.739: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.739: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.740: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.740: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.740: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.740: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.741: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.741: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.743: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.744: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.744: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.744: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.744: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.744: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.745: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.745: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.745: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.745: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.745: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.746: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.746: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.746: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.747: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.747: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.747: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.747: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.747: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.748: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.749: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.749: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.749: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:46.749: Invalid UTF-8 string passed to pango_layout_set_text()

# armamos scatterplot de precios en miles en función de superficie total
ggplot(datos_properati, aes(x = fct_reorder(l3, price, .desc = T), y = price/1000)) +
geom_boxplot(outlier.shape = NA, alpha = 0.75, aes(fill = l3)) +
theme_minimal() +
theme(legend.position = 'none')+
labs(y = "Precios en miles", x = "Barrios") +
scale_y_continuous(limits = c(0, 1200)) +
ggtitle("Boxplots de precios en función de los barrios")+
theme (axis.text.x = element_text(face="italic", colour="dark grey", size = 8, angle = 90))
(process:6086): Pango-WARNING **: 17:57:47.385: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.385: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.386: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.386: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.386: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.386: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.386: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.386: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.386: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.387: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.387: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.387: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.388: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.388: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.388: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.388: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.389: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.389: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.469: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.469: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.469: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.470: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.470: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.470: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.470: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.470: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.471: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.471: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.471: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.471: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.472: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.472: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.472: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.472: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.473: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.473: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.475: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.475: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.475: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.475: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.476: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.476: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.476: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.476: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.476: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.476: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.477: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.477: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.478: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.478: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.478: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.478: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.479: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.479: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.479: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.479: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.479: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.479: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.480: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.480: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.481: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.481: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.481: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.481: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.482: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.482: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.484: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.484: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.484: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.484: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.485: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.485: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.485: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.485: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.485: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.485: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.486: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.486: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.486: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.486: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.487: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.487: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.487: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.487: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.487: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.487: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.488: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.488: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.489: Invalid UTF-8 string passed to pango_layout_set_text()
(process:6086): Pango-WARNING **: 17:57:47.489: Invalid UTF-8 string passed to pango_layout_set_text()

En los boxplots paralelos de precios por barrios se puede ver que entre los barrios que presentan mayores precios se ubican: Puerto Madero,Las Cañitas, Catalinas, Recoleta y Belgrano, mientras que Villa Soldati, Constitución, Villa lugano y la Boca presentan los menores precios de propiedades.
Probemos ajustar un modelo lineal para el precio en función de la superficie total y los barrios.
# ajustamos el modelo
modelo_sc_l3 <- lm(price ~ surface_covered + l3, data = train_data)
tidy_sc_l3 <- tidy(modelo_sc_l3, conf.int = TRUE)
tidy_sc_l3
<<<<<<< HEAD
=======
>>>>>>> e6132d8d90ab69f2866605c879f144997998701b
R cuando efectúa la regresión calcula automáticamente las variables indicadoras (dummies) para las covariables categóricas, en general según orden alfabético. Podemos chequear el orden para verificar cuál es la categoría basal. En este caso, la categoría de referencia corresponde al barrio de Abasto.
Significado de los coeficientes estimados
¿Qué significan los coeficientes de esta variable categórica?
Este modelo propone ajustar una recta distinta para el precio medio de cada población definida por el barrio, todas con igual pendiente (definida por la superficie), y 57 ordenadas al origen diferentes, una por cada barrio.
Por ejemplo, eligiendo un barrio de precios altos, vemos que \(\beta_{Belgrano}\) indica cuánto se incrementa el precio medio de las propiedades para aquellos inmuebles ubicados en Belgrano respecto de aquellos ubicados en Abasto (categoría basal), dada la superficie.
Analizando un barrio de precios bajos, \(\beta_{Boca}\) indica cuánto se reduce el precio medio de las propiedades ubicadas en la Boca respecto de aquellas ubicadas en Abasto (categoría basal), dada la superficie.
Test F (test de significatividad global)
El test conjunto F (y su correspondiente p-valor) permite medir la significatividad conjunta de una variable categórica para explicar la respuesta.
Test F se construye para testear si varios parámetros son cero, es decir, para probar las hipótesis:
\(H_0: β_1 = β_2 = · · · = β_{p−1} = 0\)
\(H_1:\) no todos los \(β_k\) (\(k = 1, 2,..., p−1\)) son iguales a 0.
Dichos tests F se obtienen para cada variable de la tabla de ANOVA del modelo. Veamos qué ocurre en este caso.
# Modelo Superficie Total y Tipo de Propiedad
tidy(anova(modelo_sc_pt))
<<<<<<< HEAD
=======
>>>>>>> e6132d8d90ab69f2866605c879f144997998701b
La tabla de ANOVA muestra que, según el resultado del test F, la variable property_type en su conjunto resulta estadísticamente significativa para explicar al precio (p-valor < 0.05).
# Modelo Superficie Total y Barrios
tidy(anova(modelo_sc_l3))
<<<<<<< HEAD
=======
>>>>>>> e6132d8d90ab69f2866605c879f144997998701b
La tabla de ANOVA muestra que, según el resultado del test F, la variable l3 en su conjunto resulta estadísticamente significativa para explicar al precio (p-valor < 0.05). Es decir, que pese a que algunas categorías en su comparación individual con la categoría basal sean poco significativas, la variable en su conjunto sí resulta significativa para el modelo.
Si este test no resultara significativo, suele descartarse la variable categórica de entre las covariables de interés, y se la excluye del modelo. Por el contrario, si este test resulta estadísticamente significativo, entonces suelen mirarse con más detalle cuáles de las comparaciones entre grupos son estadísticamente significativas, para proporcionar un mejor análisis de los datos.
Otra alternativa sería generar una nueva variable con menor número de variables categóricas que sean significativas, sin perder capacidad explicativa. Por ejemplo, se podría armar una nueva variable que agrupe los barrios.
Generación de nueva varible tipo_barrio
Se crea una nueva variable tipo_barrio que clasifica a los barrios según el precio por metro cuadrado promedio de las propiedades en ellos, de acuerdo a precios altos, medios y bajos.
Para ello, primero se genera una nueva variable de precios por metro cuadrado pxm2 para poder generar una clasificación del barrio en base a una decisión de negocio (lo que vale en promedio el metro cuadrado en cada barrio).
# Creamos una nueva variable de precios por metro cuadrado
train_data = train_data %>%
mutate(pxm2 = round(price/surface_total,0))
# Armamos un dataframe que muestre los promedios de pxm2 en cada barrio
AVG_pxm2_l3 = train_data %>%
group_by(l3) %>%
summarise(AVG_pxm2_l3 = mean(pxm2))
AVG_pxm2_l3
<<<<<<< HEAD
=======
>>>>>>> e6132d8d90ab69f2866605c879f144997998701b
Observemos la distribución de los precios promedio por m2.
# boxplot de precios por metro cuadrado
ggplot(data = AVG_pxm2_l3, aes(x = AVG_pxm2_l3)) +
geom_boxplot(alpha = 0.75) +
labs(title = "Boxplot de precios promedio de barrios por m2") +
labs(x = "Precios promedio de barrios por m2")

Aplicaremos el siguiente criterio para agrupar los barrios en:
- precio_bajo: barrios cuyo precio promedio por m2 sea menor al Q1
- precio_medio: barrios cuyo precio promedio se encuentre en el RI
- precio_alto: barrios cuyo precio promedio por m2 sea mayor al Q3
# armamos nueva variable siguiendo tales criterios
AVG_pxm2_l3 = AVG_pxm2_l3 %>%
mutate(tipo_barrio = case_when(
AVG_pxm2_l3 < quantile(AVG_pxm2_l3)[2] ~ "precio_bajo",
AVG_pxm2_l3 >= quantile(AVG_pxm2_l3)[2] & AVG_pxm2_l3 < quantile(AVG_pxm2_l3)[4] ~ "precio_medio",
TRUE ~ "precio_alto"
)
)
write.csv(AVG_pxm2_l3, 'AVG_pxm2_l3.csv')
# write_csv(AVG_pxm2_l3, 'AVG_pxm2_l3_.csv')
# unimos esta clasificación al dataset original
train_data = train_data %>% left_join(AVG_pxm2_l3, by = 'l3')
head(train_data)
<<<<<<< HEAD
=======
>>>>>>> e6132d8d90ab69f2866605c879f144997998701b
Ajustamos el modelo con la nueva variable tipo_barrio en vez de l3.
# ajustamos el modelo
modelo_sc_tb <- lm(price ~ surface_covered + tipo_barrio, data = train_data)
tidy_sc_tb <- tidy(modelo_sc_tb, conf.int = TRUE)
tidy_sc_tb
<<<<<<< HEAD
=======
>>>>>>> e6132d8d90ab69f2866605c879f144997998701b
¿Qué pasa ahora con la significatividad de los predictores?
<<<<<<< HEAD
Colinealidad de los Predictores
Cuando las variables predictoras están correlacionadas entre sí, decimos que existe intercorrelación o multicolinealidad.
¿Qué pasa en nuestro dataset con la superficie cubierta y descubierta?
cor(train_data$surface_total, train_data$surface_covered)
[1] 0.9459646
Como ya habíamos visto en el gráfico ggpairs inicial, estas variables tienen alta correlación. Veamos qué ocurre con los coeficientes de ambas variables al armar distintos modelos múltiples que las incluyan.
Armamos un modelo con superficie total, superficie cubierta, habitaciones y tipo de propiedad.
modelo_stsc_r_pt <- lm(price ~ surface_total + surface_covered + rooms + property_type, data = train_data)
tidy(modelo_stsc_r_pt)
Armamos un modelo con superficie total y cubierta.
modelo_stsc <- lm(price ~ surface_total + surface_covered, data = train_data)
tidy(modelo_stsc)
Armamos un modelo con superficie total, habitaciones y tipo de propiedad pero sin contemplar superficie cubierta.
modelo_st_r_pt <- lm(price ~ surface_total + rooms + property_type, data = train_data)
tidy(modelo_st_r_pt)
¿Qué diferencias encuentran con los coeficientes de superficie total y cubierta en los 3 modelos?
Los coeficientes de regresión estimados se modifican sustancialmente cuando agregamos o quitamos variables del modelo. En el modelo que tiene las 4 variables vs el que solo tiene las superficies cubierta y total el beta estimado de la superficie total cambia de 918 a 412 y la cubierta de 2421 a 2516.
Los errores estándares de los estimadores de los coeficientes aumentan espúreamente cuando se incluyen covariables muy correlacionadas. Se infla la varianza estimada de los estimadores. En nuestro caso: el error estándar de la variable superficie total en el primer modelo donde está incluida la superficie cubierta es de alrededor de 918, mientras que en el modelo último que se excluye dicha variable es de 2560.
Veamos qué ocurre si en vez de usar la superficie total en el modelo último usamos la superficie cubierta.
modelo_sc_r_pt <- lm(price ~ surface_covered + rooms + property_type, data = train_data)
tidy(modelo_sc_r_pt)
Observamos que otra vez cambia el valor del estimador.
Los coeficientes pueden ser no significativos aún cuando exista una asociación verdadera entre la variable de respuesta y el conjunto de regresoras cuando armamos un modelo con multicolinealidad de variables regresoras.
Hay que tener cuidado con la colinealidad de los predictores para no tener problemas con la interpretación de los coeficientes del modelo lineal y que no aumenten espúreamente la varianza estimada de los estimadores.
Observaciones sobre la interpretación de los coeficientes
Modelo con superficies total y cubierta
La interpretación de los coeficientes estimados sería:
\(\hat{\beta_{surface\_total}}\) indica que por cada m2 adicional de superficie total el precio esperado aumenta en 412 dólares, dada la superficie cubierta.
\(\hat{\beta_{surface\_covered}}\) indica que por cada m2 adicional de superficie cubierta el precio esperado aumenta en 2516 dólares, dada la superficie total.
Respecto a la segunda interpretación alguien podría objetar lo siguiente:
\(surface\_total = suface\_covered + suface\_uncovered\)
Entonces, si aumento en un m2 la superficie cubierta no puedo sostener que variable superficie total se mantiene constante.
¿Es esta observación correcta?
El coeficiente de \(\hat{\beta_{surface\_total}}\) en realidad nos permite evaluar cual es el efecto en el precio esperado de un m2 más de superficie descubierta para igual cantidad de m2 de superficie cubierta. Es decir, lo que cambia es la interpretación en este caso de dicho coeficiente.
Por ejemplo, si existen dos propiedades de 50m2 de superficie total y la propiedad A tiene 5 m2 de superficie descubierta y la propiedad B 4 m2, nuestro modelo nos indica que el precio predicho para la propiedad B va a ser 412 dólares menor al precio de la propiedad A.
Modelo superficies cubierta y descubierta
Si quisieramos poder separar el efecto de la superficie cubierta y descubierta deberíamos crear una variable nueva que sea:
\(surface\_uncovered = suface\_total + suface\_covered\)
Ahora nuestro modelo es:
\(E(precio|...) = \beta_0 + \beta_{sc}surface\_covered + \beta_{su}surface\_uncovered\)
Para ello creamos una nueva variable de superficie descubierta que sea resultado de la resta entre superficie total y cubierta.
df2 = train_data %>%
mutate(surface_uncovered = surface_total - surface_covered)
Construimos el modelo lineal que planteamos
tidy(lm(price ~ surface_covered + surface_uncovered, data = df2))
La interpretación de los coeficientes estimados es:
\(\hat{\beta_{suface\_covered}}\) indica que por cada m2 adicional de superficie cubierta el precio esperado de las propiedades aumenta en 2.929 dólares, dada la superficie descubierta.
\(\hat{\beta_{suface\_uncovered}}\) indica que por cada m2 adicional de superficie descubierta el precio esperado aumenta 412 dólares, dada la superficie cubierta.
En este caso la regresión ayuda a entender cómo afecta la superficie cubierta y descubierta al precio del inmueble. Es decir, cuánto aumenta el precio medio un m2 adicional de superficie cubierta, dada la superficie descubierta, y cuánto aumenta el precio promedio un m2 adicional de superficie descubierta, dada la superficie cubierta.
Volvemos a observar que el p valor asociado a \(\beta_2\) indica que no se puede rechazar la hipotesis nula del test de significatividad individual.
=======
>>>>>>> e6132d8d90ab69f2866605c879f144997998701b
LS0tCnRpdGxlOiAiUmVncmVzacOzbiBMaW5lYWwgTcO6bHRpcGxlIEkiCmF1dGhvcjogIkp1YW4gQmFycmlvbGEgeSBTb2bDrWEgUGVyaW5pIgpkYXRlOiAiMjUgZGUgU2VwdGllbWJyZSBkZSAyMDIxIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICBkZl9wcmludDogcGFnZWQKLS0tCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpkaXYubWFpbi1jb250YWluZXIgewogIG1heC13aWR0aDogMTYwMHB4OwogIG1hcmdpbi1sZWZ0OiBhdXRvOwogIG1hcmdpbi1yaWdodDogYXV0bzsKfQo8L3N0eWxlPgogIAojIyBQbGFudGVvIGRlbCBwcm9ibGVtYQoKTnVlc3RybyBvYmpldGl2byBlcyBjcmVhciB1biBtb2RlbG8gbGluZWFsIG3Dumx0aXBsZSBwYXJhIGV4cGxpY2FyIGVsIHByZWNpbyBkZSB2ZW50YSBlbiBkw7NsYXJlcyBkZSBsYXMgcHJvcGllZGFkZXMgZW4gQ2FwaXRhbCBGZWRlcmFsIHJlcG9ydGFkYXMgcG9yIGxhIGVtcHJlc2EgW1Byb3BlcmF0aSBBcmdlbnRpbmFdKGh0dHBzOi8vd3d3LnByb3BlcmF0aS5jb20uYXIvKS4gCgpWYW1vcyBhIHV0aWxpemFyIGRhdG9zIGRlbCAyMDE5IHBhcmEgbm8gaW5jb3Jwb3JhciBjb21wb3J0YW1pZW50b3MgYXTDrXBpY29zIG9jYXNpb25hZG9zIHBvciBsYSBwYW5kZW1pYSBkZWwgQ09WSUQtMTkuCgpOdWVzdHJhIGlkZWEgc3VieWFjZW50ZSBkZSBjw7NtbyBzZSBwdWVkZSBleHBsaWNhciBlbCBwcmVjaW8gZXM6CgokcHJlY2lvID0gXGJldGFfMCArXGJldGFfMVhfMStcYmV0YV8yWF8yKy4uLitcZXBzaWxvbiQKCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGlkeW1vZGVscykKbGlicmFyeShyc2FtcGxlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoR0dhbGx5KQpgYGAKCiMjIExldmFudGFtb3MgRGF0YXNldAoKVmFtb3MgYSB0cmFiYWphciBjb24gdW4gc3ViY29uanVudG8gZGUgZGF0b3MgcXVlIHN1cmdpw7MgZGUgdW4gdHJhYmFqbyBkZSBsaW1waWV6YSB5IHRyYXRhbWllbnRvIGRlIG91dGxpZXJzIHF1ZSBzZSBwdWVkZSBjb25zdWx0YXIgZW4gZWwgbm90ZWJvb2sgZGUgUHJlcHJvY2VzYW1pZW50byBEYXRhc2V0IFByb3BlcmF0aSwgY29ycmVzcG9uZGllbnRlIGEgcHJlY2lvcyBkZSBwcm9waWVkYWRlcyBlbiBDYXBpdGFsIEZlZGVyYWwsIGN1eW8gcHJlY2lvIGVzdMOhIGV4cHJlc2FkbyBlbiBkb2xhcmVzIChVU0QpLCBlbCB0aXBvIGRlIHByb3BpZWRhZCBjb3JyZXNwb25kZSBhIERlcGFydGFtZW50bywgUEggbyBDYXNhLCB5IGVsIHRpcG8gZGUgb3BlcmFjaW9uIHNlYSBWZW50YS4gCgpgYGB7ciwgbWVzc2FnZT1GfQpkYXRvc19wcm9wZXJhdGkgPC0gcmVhZC5jc3YoInByb3BlcmF0aV9wcmVwcm9jZXNhZG8uY3N2IikKZ2xpbXBzZShkYXRvc19wcm9wZXJhdGkpCmBgYAoKTGEgbGltcGllemEgY29uc2lzdGnDsyBlbjogZWxpbWluYXIgbGEgdmFyaWFibGUgYmVkcm9vbXMgcG9yIHJlZ2lzdHJhciBncmFuIHByZXNlbmNpYSBkZSBmYWx0YW50ZXMgKDQwJSkgeSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgZnVlcnRlIGNvbiBsYSB2YXJpYWJsZSByb29tcyAoMC45NyksIGVsaW1pbmFyIGxvcyByZWdpc3Ryb3MgY29uIGZhbHRhbnRlcywgZGVzY2FydGFyIHJlZ2lzdHJvcyBkb25kZSBsYSBzdXBlcmZpY2llIHRvdGFsIHJlc3VsdGEgaW5mZXJpb3IgYSBsYSBjdWJpZXJ0YSwgcG9yIHRyYXRhcnNlIHByb2JhYmxlbWVudGUgZGUgYWxnw7puIGVycm9yIGRlIGNhcmdhLiBQb3Igw7psdGltbywgc2UgcmVhbGl6w7MgdW4gdHJhdGFtaWVudG8gZGUgbG9zIG91dGxpZXJzLCBlbXBsZWFuZG8gbGFzIHTDqWNuaWNhcyB2aXN0YXMgZW4gbGEgY2xhc2UgMywgcXVlZGFuZG8gY29tbyByZXN1bHRhZG8gdW4gZGF0YXNldCBkZSA0OS44MzUgb2JzZXJ2YWNpb25lcyB5IDkgY29sdW1uYXMsIGNvbiBlbCBxdWUgdHJhYmFqYXJlbW9zIGEgY29udGludWFjacOzbi4gCgojIyMgU2VsZWNjaW9uYW1vcyB2YXJpYWJsZXMgZGUgaW50ZXLDqXMKCkVuIGVzdGUgY2FzbyB5YSBlc3TDoW4gcHJlc2VsZWNjaW9uYWRhcyA5IHZhcmlhYmxlczoKCi0gKmlkKjogaWRlbnRpZmljYWNpb24uCi0gKmwzKjogYmFycmlvLgotICpyb29tcyo6IG5ybyBkZSBoYWJpdGFjaW9uZXMuCi0gKmJhdGhyb29tcyo6IG5ybyBkZSBiYcOxb3MKLSAqc3VyZmFjZV90b3RhbCo6IHN1cGVyZmljaWUgdG90YWwgZW4gbTIKLSAqc3VyZmFjZV9jb3ZlcmVkKjogc3VwZXJmaWNpZSBjdWJpZXJ0YSBlbiBtMgotICpwcmljZSo6IHByZWNpbyAodmFyaWFibGUgYSBwcmVkZWNpcikgZW4gZMOzbGFyZXMKLSAqcHJvcGVydHlfdHlwZSo6IHRpcG8gZGUgcHJvcGllZGFkIChEZXBhcnRhbWVudG8sIFBIIG8gQ2FzYSkKLSAqcHJlY2lvX2VuX21pbGVzKjogdmFyaWFibGUgY3JlYWRhIHBvciBub3NvdHJvcyBwYXJhIGdyYWZpY2FyIAoKYGBge3J9CmRhdG9zX3Byb3BlcmF0aSAlPiUKICBoZWFkKCkKYGBgCgpWZWFtb3MgY8OzbW8gZXMgbGEgY29ycmVsYWNpw7NuIGVudHJlIGxhcyB2YXJpYWJsZXMgbnVtw6lyaWNhcy4gCgpgYGB7ciwgcHJvZ3Jlc3M9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsICB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OH0KIyBncmFmaWNhbW9zIGNvbiBnZ3BhaXJzIGNvbG9yZWFuZG8gcG9yIHByb3BlcnR5IHR5cGUKZyA8LSBnZ3BhaXJzKGRhdG9zX3Byb3BlcmF0aSAlPiUgc2VsZWN0KC1jKGlkLGwzKSksIGFlcyhjb2xvciA9IHByb3BlcnR5X3R5cGUpLCAKICAgICAgICAgIHVwcGVyID0gbGlzdChjb250aW51b3VzID0gd3JhcCgiY29yIiwgc2l6ZSA9IDMsIGhqdXN0PTAuNSkpLCBsZWdlbmQgPSAyNSkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKyAKICB0aGVtZV9idygpCiMgaGFjZW1vcyB1biBsb29wIHBhcmEgY2FtYmlhciBsb3MgY29sb3JlcyBkZWwgZ3LDoWZpY28KZm9yKGkgaW4gMTpnJG5yb3cpIHsKICBmb3IoaiBpbiAxOmckbmNvbCl7CiAgICBnW2ksal0gPC0gZ1tpLGpdICsgCiAgICAgIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IkRhcmsyIikgKyAgCiAgICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJEYXJrMiIpCiAgICAgICAgfQp9CmcgCmBgYAoKKiBMYXMgdmFyaWFibGVzIHN1cGVyZmljaWUgY3ViaWVydGEgeSB0b3RhbCBwcmVzZW50YW4gdW5hIGFzb2NpYWNpw7NuIGxpbmVhbCBwb3NpdGl2YSBmdWVydGUgKDAuOTQ1KS4KClJlc3BlY3RvIGRlIG51ZXN0cmEgdmFyaWFibGUgYSBwcmVkZWNpciwgZWwgcHJlY2lvLCBvYnNlcnZhbW9zIHF1ZToKCiogRXhpc3RlIHVuYSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgZnVlcnRlIGNvbiBsYXMgc3VwZXJmaWNpZXMgdG90YWwgeSBjdWJpZXJ0YS4gUmVzcGVjdG8gYSBlc3RhcyDDumx0aW1hcyBleGlzdGUgdW5hIGdyYW4gZGlmZXJlbmNpYSBlbiBsYSBjb3JyZWxhY2nDs24gc2Vnw7puIGVsIHRpcG8gZGUgcHJvcGllZGFkLiBMYXMgY2FzYXMgcGFyZWNlbiBwcmVzZW50YXIgbWVub3IgY29ycmVsYWNpw7NuIHF1ZSBsb3MgZGVwYXJ0YW1lbnRvcyB5IFBIcy4KCiogRXhpc3RlIHVuYSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgbWVub3IgY29uIGVsIG7Dum1lcm8gZGUgaGFiaXRhY2lvbmVzIHkgYmHDsW9zLiAKCiMjIFBhcnRpY2nDs24gZGVsIGRhdGFzZXQgZW4gdHJhaW4geSB0ZXN0CgpFbiBlc3RlIGNhc28gcGFyYSBldmFsdWFyIGxvcyBtb2RlbG9zIHZhbW9zIGEgcmVhbGl6YXIgdW5hIHBhcnRpY2nDs24gZW50cmUgZGF0YXNldCBkZSBlbnRyZW5hbWllbnRvICg3NSUpIHkgdGVzdGVvICgyNSUpIHVzYW5kbyBsYSBmdW5jacOzbiBgaW5pdGlhbF9zcGxpdGAgZGVsIHBhcXVldGUgW3JzYW1wbGVdKGh0dHBzOi8vcnNhbXBsZS50aWR5bW9kZWxzLm9yZy8pIGRlIHRpZHltb2RlbHMuCgpgYGB7cn0KIyBmaWphbW9zIHNlbWlsbGEKc2V0LnNlZWQoMjAyMSkKIyBQYXJ0aWNpw7NuIFRyYWluIHkgVGVzdCwgaW5kaWNhbmRvIHByb3BvcmNpw7NuCnRyYWluX3Rlc3QgPC0gaW5pdGlhbF9zcGxpdChkYXRvc19wcm9wZXJhdGksIHByb3AgPSAwLjc1KQp0cmFpbl9kYXRhIDwtIHRyYWluaW5nKHRyYWluX3Rlc3QpCnRlc3RfZGF0YSA8LSB0ZXN0aW5nKHRyYWluX3Rlc3QpCiMgdmVtb3MgbGFzIGRpbWVuc2lvbmVzIGRlIGNhZGEgcGFydGljaW9uCnRyYWluX2RhdGEgJT4lCiAgZGltX2Rlc2MoKSAKdGVzdF9kYXRhICU+JQogIGRpbV9kZXNjKCkgCmBgYApFbCBkYXRhc2V0IGRlIHRlc3QgbG8gdXRpbGl6YXJlbW9zIGVuIGxhIHNpZ3VpZW50ZSBjbGFzZS4gCgojIyBNb2RlbG8gTcO6bHRpcGxlCgpFbCBtb2RlbG8gZGUgKipyZWdyZXNpw7NuIGxpbmVhbCBtw7psdGlwbGUqKiBlcyB1biBtb2RlbG8gcGFyYSBsYSB2YXJpYWJsZSBhbGVhdG9yaWEgWSBjdWFuZG8gc2UgY29ub2NlbiBsYXMgdmFyaWFibGVzIHJlZ3Jlc29yYXMuIEVzIG3Dumx0aXBsZSB5YSBxdWUgdmluY3VsYSB1bmEgc2VyaWUgZGUgdmFyaWFibGVzIHByZWRpY3RvcmFzIGNvbiBZLiAKCkVsIG1vZGVsbyBlbiB0w6lybWlub3MgZGUgbGFzIHZhcmlhYmxlczoKCiQkWV9pID0gzrJfMCArIM6yXzFYX3tpMX0gKyDOsl8yWF97aTJ9ICsgwrcgwrcgwrcgKyDOsl97cC0xfVhfe2lwLTF9ICsgzrVfaSQkCmRvbmRlICTOsl8wJCwgJM6yXzEkLC4uLCAkzrJfe3DiiJIxfSQgc29uIHBhcsOhbWV0cm9zIGRlc2Nvbm9jaWRvcywgJFhfe2kxfSQsICRYX3tpMn0kLCAuLi4sICRYX3tpcC0xfSQgc29uIGxvcyB2YWxvcmVzIGRlIGxhcyB2YXJpYWJsZXMgcHJlZGljdG9yYXMgbWVkaWRhcyBlbiBlbCBpLcOpc2ltbyBpbmRpdmlkdW8sICRZX2kkIGVzIGxhIHZhcmlhYmxlIHJlc3B1ZXN0YSBtZWRpZGEgZW4gZWwgaS3DqXNpbW8gaW5kaXZpZHVvIChvYnNlcnZhZG8pIHkgJM61X2kkIGVzIGVsIGVycm9yIHBhcmEgZWwgaW5kaXZpZHVvIGktw6lzaW1vIChubyBvYnNlcnZhYmxlKS4KCioqU3VwdWVzdG9zIGRlbCBtb2RlbG8gbGluZWFsKioKClNlIHB1ZWRlbiByZXN1bWlyIGNvbW8gJM+1X2kkIH4gJE4oMCzPg14yKSQgcGFyYSB0b2RvICQxPGk8biQsIGluZGVwZW5kaWVudGVzIGVudHJlIHPDrS4KCkVsIG1vZGVsbyBlbiB0w6lybWlub3MgZGUgbGEgZXNwZXJhbnphIGNvbmRpY2lvbmFsIGRlIFkgZGFkYXMgJFhfMSQsICRYXzIkLC4uLiwgJFhfe3AtMX0kOgoKJCRFKFl8WF8xLFhfMiwuLi5YX3twLTF9KSA9IM6yXzAgKyDOsl8xWF97aTF9ICsgzrJfMlhfe2kyfSArIMK3IMK3IMK3ICsgzrJfe3AtMX1YX3tpcC0xfSQkCgpFbCBtb2RlbG8gc2UgZGVub21pbmEgKmxpbmVhbCogcHVlc3RvIHF1ZSBsYSBlc3BlcmFuemEgZGUgWSBjb25kaWNpb25hbCBhIGxhcyBYJ3MgZGVwZW5kZSBsaW5lYWxtZW50ZSBkZSBsYXMgY292YXJpYWJsZXMgJFhfMSQsICRYXzIkLC4uLiwgJFhfe3AtMX0kLiAKCiMjIyBFc3RpbWFjacOzbiBkZSBsb3MgUGFyw6FtZXRyb3MgKGFqdXN0ZSBkZWwgbW9kZWxvKQoKU2UgcXVpZXJlIGFqdXN0YXIgdW4gbW9kZWxvIHBhcmEgZWwgcHJlY2lvIGRlIGxhcyBwcm9waWVkYWRlcyBlbiBmdW5jacOzbiBkZSAyIHZhcmlhYmxlczoKCiRwcmVjaW8gPSBcYmV0YV8wICsgXGJldGFfMXhfe2kxfSArIFxiZXRhXzJ4X3tpMn0gKyBcZXBzaWxvbl9pJAoKVmVhbW9zIGPDs21vIHNlIGludGVycHJldGFuIGxvcyBhanVzdGVzIHBhcmEgbG9zIGRpc3RpbnRvcyB0aXBvcyBkZSBwcmVkaWN0b3Jlcy4gCgojIyMgKjEpIFByZWRpY3RvcmVzIG51bcOpcmljb3MqCgpBcm1lbW9zIHVuIG1vZGVsbyBwYXJhIHByZWRlY2lyIGVsIHByZWNpbyBlbiBmdW5jacOzbiBkZSBsYSBzdXBlcmZpY2llIGN1YmllcnRhIHkgbGEgY2FudGlkYWQgZGUgaGFiaXRhY2lvbmVzLiBWZWFtb3MgbG9zIHJlc3VsdGFkb3MgZGVsIG1vZGVsbyBlbXBsZWFuZG8gbGEgZnVuY2nDs24gdGlkeSgpLiAKCmBgYHtyfQojIGFqdXN0YW1vcyBtb2RlbG8gbGluZWFsIG11bHRpcGxlCm1vZGVsb19zY19yIDwtIGxtKHByaWNlIH4gc3VyZmFjZV9jb3ZlcmVkICsgcm9vbXMsIGRhdGEgPSB0cmFpbl9kYXRhKQojIFJlc3VtZW4gZGVsIG1vZGVsbwp0aWR5X3NjX3IgPC0gdGlkeShtb2RlbG9fc2NfciwgY29uZi5pbnQgPSBUUlVFKQp0aWR5X3NjX3IKYGBgCgojIyMjIFNpZ25pZmljYWRvIGRlIGxvcyBjb2VmaWNpZW50ZXMgZXN0aW1hZG9zCgoqIEVsIHZhbG9yIGRlICRcaGF0e1xiZXRhXzB9JCAob3JkZW5hZGEgYWwgb3JpZ2VuKSBlcyBgciByb3VuZCh0aWR5X3NjX3IkZXN0aW1hdGVbMV0pYCBkw7NsYXJlcywgbG8gcXVlIGNvcnJlc3BvbmRlIGFsIHByZWNpbyAqKmVzcGVyYWRvKiogZGUgdW5hIHByb3BpZWRhZCBjb24gMCBoYWJpdGFjaW9uZXMgeSBzaW4gc3VwZXJmaWNpZS4gTG8gY3VhbCwgZXN0ZSBjYXNvIGNhcmVjZXLDrWEgZGUgc2VudGlkbyB5YSBxdWUgbGFzIHByb3BpZWRhZGVzIGRlYmVyw61hbiB0ZW5lciBzdXBlcmZpY2llIHkgYWwgbWVub3MgYWxndW5hIGhhYml0YWNpw7NuL2FtYmllbnRlLiAgCgoqIEVsIGNvZWZpY2llbnRlIGVzdGltYWRvIGRlICRcaGF0e1xiZXRhX3tzdXJmYWNlXF9jb3ZlcmVkfX0kIChzdXBlcmZpY2llIGN1YmllcnRhKSBlcyBkZSBgciByb3VuZCh0aWR5X3NjX3IkZXN0aW1hdGVbMl0pYCBkw7NsYXJlcywgbG8gcXVlIGluZGljYSBxdWUgc2kgbWFudGVuZW1vcyBlbCBuw7ptZXJvIGRlIGhhYml0YWNpb25lcyBjb25zdGFudGUsIGNhZGEgaW5jcmVtZW50byBkZSB1biBtMiBhZGljaW9uYWwgZGUgc3VwZXJmaWNpZSBjb3JyZXNwb25kZSBhIHVuIGF1bWVudG8gZGUgYHIgcm91bmQodGlkeV9zY19yJGVzdGltYXRlWzJdKWAgZMOzbGFyZXMsICoqZW4gcHJvbWVkaW8qKiBlbiBlbCBwcmVjaW8gZGUgbGEgcHJvcGllZGFkLiBPIGxvIHF1ZSBlcyBpZ3VhbCwgZGFkYXMgZG9zIHByb3BpZWRhZGVzIGNvbiBsYSBtaXNtYSBjYW50aWRhZCBkZSBoYWJpdGFjaW9uZXMgcGVybyB0ZW5pZW5kbyB1bmEgdW4gbTIgbcOhcyBkZSBzdXBlcmZpY2llIHF1ZSBsYSBvdHJhLCBlbCBwcmVjaW8gKiplc3BlcmFkbyoqIHBhcmEgbGEgZGUgbWF5b3Igc3VwZXJmaWNpZSBzZXLDoSBgciByb3VuZCh0aWR5X3NjX3IkZXN0aW1hdGVbMl0pYCBkw7NsYXJlcyBtw6FzIGFsdG8gcXVlIGxhIGRlIG1lbm9yIHN1cGVyZmljaWUuCgrCv0PDs21vIHNlIGludGVycHJldGFyw61hIGVsIGNvZWZpY2llbnRlIGVzdGltYWRvIGRlbCBuw7ptZXJvIGRlIGhhYml0YWNpb25lcz8KCiMjIyAqMikgUHJlZGljdG9yZXMgQ2F0ZWfDs3JpY29zKgoKQXJtZW1vcyB1biBtb2RlbG8gcGFyYSBwcmVkZWNpciBlbCBwcmVjaW8gZGUgbGEgcHJvcGllZGFkIGVuIGZ1bmNpw7NuIGRlIGxhIHN1cGVyZmljaWUgY3ViaWVydGEgeSBlbCB0aXBvIGRlIHByb3BpZWRhZCAoKnByb3BlcnR5X3R5cGUqKSwgcXVlIGVzIGNhdGVnw7NyaWNhIGNvbiB0cmVzIG5pdmVsZXMgKENhc2EsIERlcGFydGFtZW50byBvIFBIKS4gUGFyYSBlbGxvLCB2YW1vcyBhIGFuYWxpemFyIHByaW1lcm8gZWwgY29tcG9ydGFtaWVudG8gZGUgbGEgdmFyaWFibGUgcXVlIHF1ZXJlbW9zIHByZWRlY2lyIHBhcmEgY2FkYSB0aXBvIGRlIHByb3BpZWRhZCBhIHRyYXbDqXMgZGUgdW4gYm94cGxvdC4gCgpgYGB7cn0KIyBhcm1hbW9zIGJveHBsb3RzIHBhcmFsZWxvcyBkZSBwcmVjaW8gc2VndW4gZWwgdGlwbyBkZSBwcm9waWVkYWQgKGNhc2EsIGRwdG8gbyBwaCkKZ2dwbG90KGRhdGEgPSB0cmFpbl9kYXRhLCBhZXMoeSA9IHByZWNpb19lbl9taWxlcywgZ3JvdXAgPSBwcm9wZXJ0eV90eXBlLCBmaWxsID0gcHJvcGVydHlfdHlwZSkpICsKICAgICAgICAgZ2VvbV9ib3hwbG90KCkgKyAKICAgICAgICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iRGFyazIiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCkpICsKICAgICAgICAgbGFicyh0aXRsZSA9ICJCb3hwbG90cyBkZSBwcmVjaW8gc2Vnw7puIHRpcG8gZGUgcHJvcGllZGFkIiwgc3VidGl0bGUgPSAiRW4gbWlsZXMgZGUgZMOzbGFyZXMiKSArCiAgbGFicyh5ID0gIlByZWNpbyBlbiBtaWxlcyBkZSBVU0QiKSArCiAgbGFicyh4ID0gIlRpcG8gZGUgcHJvcGllZGFkIikgKwogIGZhY2V0X3dyYXAofnByb3BlcnR5X3R5cGUpCmBgYApgYGB7cn0KIyBBY290YW5kbyBsYSBlc2NhbGEgZGVsIGdyYWZpY28gcGFyYSB2aXN1YWxpemFyIG1lam9yIGVsIHJhbmdvIGludGVyY3VhcnRpbApnZ3Bsb3QoZGF0YSA9IHRyYWluX2RhdGEsIGFlcyh5ID0gcHJlY2lvX2VuX21pbGVzLCBncm91cCA9IHByb3BlcnR5X3R5cGUsIGZpbGwgPSBwcm9wZXJ0eV90eXBlKSkgKwogICAgICAgICBnZW9tX2JveHBsb3QoKSArIAogICAgICAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJEYXJrMiIpICsKICB0aGVtZV9idygpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxMDAwKSkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKSArCiAgICAgICAgIGxhYnModGl0bGUgPSAiQm94cGxvdHMgZGUgcHJlY2lvIHNlZ8O6biB0aXBvIGRlIHByb3BpZWRhZCIsIHN1YnRpdGxlID0gIkVuIG1pbGVzIGRlIGTDs2xhcmVzIikgKwogIGxhYnMoeSA9ICJQcmVjaW8gZW4gbWlsZXMgZGUgVVNEIikgKwogIGxhYnMoeCA9ICJUaXBvIGRlIHByb3BpZWRhZCIpICsKICBmYWNldF93cmFwKH5wcm9wZXJ0eV90eXBlKQpgYGAKQW5hbGl6YW5kbyBsYSB2YXJpYWJsZSBkZSAqdGlwbyBkZSBwcm9waWVkYWQqIGVuIGZ1bmNpw7NuIGRlIGxhIHZhcmlhYmxlIGEgcHJlZGVjaXIsIHNlIG9ic2VydmEgdW5hIGRpZmVyZW5jaWEgZW4gbG9zIHByZWNpb3Mgc2Vnw7puIGVsIHRpcG8gZGUgcHJvcGllZGFkLiBFbiBwYXJ0aWN1bGFyLCBsYXMgY2FzYXMgcHJlc2VudGFuIG1heW9yZXMgcHJlY2lvcyB5IGEgc3UgdmV6LCBtYXlvciB2YXJpYWJpbGlkYWQgcXVlIGxvcyBkZXBhcnRhbWVudG9zIHkgUEhzLiAKClZlYW1vcyBxdcOpIG9jdXJyZSBjdWFuZG8gKiphanVzdGFtb3MgZWwgbW9kZWxvKio6CgpgYGB7cn0KIyBhanVzdGFtb3MgZWwgbW9kZWxvIGRlIHN1cGVyZmljaWUgeSB0aXBvIGRlIHByb3BpZWRhZAptb2RlbG9fc2NfcHQgPC0gbG0ocHJpY2UgfiBzdXJmYWNlX2NvdmVyZWQgKyBwcm9wZXJ0eV90eXBlLCBkYXRhID0gdHJhaW5fZGF0YSkKdGlkeV9zY19wdCA8LSB0aWR5KG1vZGVsb19zY19wdCwgY29uZi5pbnQgPSBUUlVFKQp0aWR5X3NjX3B0CmBgYAoKIyMjIyBTaWduaWZpY2FkbyBkZSBsb3MgY29lZmljaWVudGVzIGVzdGltYWRvcwoKwr9Dw7NtbyBjYW1iaWEgbGEgKippbnRlcnByZXRhY2nDs24qKiBkZSBsb3MgY29lZmljaWVudGVzIHBhcmEgbGEgdmFyaWFibGUgY2F0ZWfDs3JpY2E/CgpFbCBtb2RlbG8gZGUgcmVncmVzacOzbiBsaW5lYWwgZW4gZXN0ZSBjYXNvIGNvbnNpc3RlIHNpbXBsZW1lbnRlIGVuIGV4cHJlc2FyCmxhIG1lZGlhIGRlbCBuaXZlbCBkZSBwcmVjaW9zIGVuIGNhZGEgcG9ibGFjacOzbiAoZGUgY2FzYXMsIGRlcGFydGFtZW50b3MgbyBQSHMpIG1lZGlhbnRlIHRyZXMgY29lZmljaWVudGVzIGRpc3RpbnRvcywgZG9uZGU6IAoKKiAkXGJldGFfMCQgKGNhdGVnb3LDrWEgYmFzYWwgZGUgdmFyaWFibGUgY2F0ZWfDs3JpY2EpIGVzIGxhIG1lZGlhIGRlbCBwcmVjaW8gcGFyYSBsYXMgQ2FzYXMgc2luIHN1cGVyZmljaWUuIEVuIGVzdGUgbW9kZWxvIGVzIGRlIGByIHJvdW5kKHRpZHlfc2NfcHQkZXN0aW1hdGVbMV0pYCBkw7NsYXJlcywgbG8gcXVlIGNhcmVjZSBkZSBzZW50aWRvIGVjb27Ds21pY28geWEgcXVlIGxhcyBjYXNhcyBkZWJlcsOtYW4gdGVuZXIgYWxndW5hIHN1cGVyZmljaWUgeSBubyBwb2Ryw61hbiB0ZW5lciB1biBwcmVjaW8gbmVnYXRpdm8uICAKCiogJFxiZXRhXzAgKyBcYmV0YV97cHJvcGVydHlcX3R5cGVEZXBhcnRhbWVudG99JCBlcyBsYSBtZWRpYSBkZWwgcHJlY2lvIHBhcmEgbG9zIGRlcGFydGFtZW50b3MsIGRhZGEgbGEgc3VwZXJmaWNpZS4gUG9yIGxvIHRhbnRvLCAkXGJldGFfe3Byb3BlcnR5XF90eXBlRGVwYXJ0YW1lbnRvfSQgZXMgbGEgZGlmZXJlbmNpYSBlbiBsb3MgKipuaXZlbGVzIG1lZGlvcyoqIGRlIHByZWNpb3MgZGUgbG9zIGRlcGFydGFtZW50b3MgcmVzcGVjdG8gZGUgbGFzIGNhc2FzIChjYXRlZ29yw61hIGJhc2FsKS5FcyBkZWNpciwgJFxiZXRhX3twcm9wZXJ0eVxfdHlwZURlcGFydGFtZW50b30kIChgciByb3VuZCh0aWR5X3NjX3B0JGVzdGltYXRlWzNdKWApIGluZGljYSBjdcOhbnRvIG3DoXMgYWx0YSBlcyBsYSBmdW5jacOzbiBkZSByZXNwdWVzdGEgKHByZWNpbykgcGFyYSBsb3MgZGVwYXJ0YW1lbnRvcyByZXNwZWN0byBkZSBsYXMgY2FzYXMgKGNhdGVnb3LDrWEgYmFzYWwpLCBkYWRhIGxhIHN1cGVyZmljaWUuCgoqIFZlbW9zIHF1ZSBlbCBuaXZlbCBtZWRpbyBkZWwgcHJlY2lvIGVzIHVuYSBmdW5jacOzbiBsaW5lYWwgZGUgbGEgc3VwZXJmaWNpZSBkZSBsYSBwcm9waWVkYWQsIGNvbiB1bmEgbWlzbWEgcGVuZGllbnRlICRcYmV0YV97c3VyZmFjZV90b3RhbH0kIGByIHJvdW5kKHRpZHlfc2NfcHQkZXN0aW1hdGVbMl0pYCBwYXJhIGNhc2FzLCBkZXBhcnRhbWVudG9zIHkgUEhzLiAKCsK/Q8OzbW8gc2UgaW50ZXJwcmV0YXLDrWEgZW50b25jZXMgJFxiZXRhX3twcm9wZXJ0eVxfdHlwZVBIfSQ/IMK/WSAkXGJldGFfMCArIFxiZXRhX3twcm9wZXJ0eVxfdHlwZVBIfSQ/CgojIyMjIEdyYWZpcXVlbW9zIGxhIHJlZ3Jlc2nDs24gcGFyYSBsYXMgdHJlcyBwb2JsYWNpb25lcwoKQSBjb250aW51YWNpw7NuIHNlIG11ZXN0cmEgZWwgZ3LDoWZpY28gZGUgZXN0YSBzaXR1YWNpw7NuIGVuIHF1ZSB0ZW5lbW9zIHVuYSB2YXJpYWJsZSBjYXRlZ8OzcmljYSBjb24gdHJlcyBuaXZlbGVzIHkgdW5hIG51bcOpcmljYS4gRGUgbGEgaW50ZXJwcmV0YWNpw7NuIGRlIGNvZWZpY2llbnRlcywgc2UgcHVkbyB2ZXIgcXVlIGxhIHJlZ3Jlc2nDs24gc2UgcHVlZGUgZXhwcmVzYXIgY29tbyByZWN0YXMgcGFyYWxlbGFzIGNvbiBpZ3VhbCBwZW5kaWVudGUgcGVybyBkaXN0aW50byBpbnRlcmNlcHRvLiBWZWFtb3MgY8OzbW8gaGFjZXJsYS4gCgpgYGB7cn0KIyBBY2NlZGVtb3MgYSBsYSBpbmZvcm1hY2nDs24gZGUgbG9zIGNvZWZpY2llbnRlcyBlc3RpbWFkb3MKaW50ZXJjZXB0b19DID0gbW9kZWxvX3NjX3B0JGNvZWZmaWNpZW50c1sxXSAjIM6yMApwZW5kaWVudGUgPSBtb2RlbG9fc2NfcHQkY29lZmZpY2llbnRzWzJdICMgzrIxCmludGVyY2VwdG9fRCA9IG1vZGVsb19zY19wdCRjb2VmZmljaWVudHNbMV0gKyBtb2RlbG9fc2NfcHQkY29lZmZpY2llbnRzWzNdICMgzrIwICsgzrIyCmludGVyY2VwdG9fUEggPSBtb2RlbG9fc2NfcHQkY29lZmZpY2llbnRzWzFdICsgbW9kZWxvX3NjX3B0JGNvZWZmaWNpZW50c1s0XSAjIM6yMCArIM6yMwojIEdyYWZpY2Ftb3MgZWwgZGF0YXNldCB5IGVsIG1vZGVsbwp0cmFpbl9kYXRhICU+JSBnZ3Bsb3QoLiwgYWVzKHggPSBzdXJmYWNlX2NvdmVyZWQsIHkgPSBwcmljZSkpICsgCiAgZ2VvbV9wb2ludCgpICsgI2NhcGEgZGUgbG9zIGRhdG9zCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gaW50ZXJjZXB0b19DLCBzbG9wZSA9IHBlbmRpZW50ZSwgY29sb3IgPSAiZm9yZXN0Z3JlZW4iLCBzaXplPTEpICsgIyBjYXBhIGRlbCBtb2RlbG8KICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSBpbnRlcmNlcHRvX0QsIHNsb3BlID0gcGVuZGllbnRlLCBjb2xvciA9ICJkYXJrb3JhbmdlIiwgc2l6ZT0xKSArICMgY2FwYSBkZWwgbW9kZWxvIAogICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gaW50ZXJjZXB0b19QSCwgc2xvcGUgPSBwZW5kaWVudGUsIGNvbG9yID0gInNsYXRlYmx1ZTMiLCBzaXplPTEpICsgIyBjYXBhIGRlbCBtb2RlbG8gCiAgdGhlbWVfYncoKSArCiAgbGFicyh0aXRsZT0iTW9kZWxvIExpbmVhbCBNw7psdGlwbGU6IFN1cGVyZmljaWUgeSBUaXBvIGRlIFByb3BpZWRhZCIsIHg9IlN1cGVyZmljaWUgZW4gbTIiLCB5PSJQcmVjaW8gZW4gbWlsZXMgZGUgVVNEIikgCmBgYAoKIyMjICpQcmVkaWN0b3JlcyBDdWFsaXRhdGl2b3MgY29uIG11Y2hhcyBjbGFzZXMqCgpMYSB2YXJpYWJsZSBiYXJyaW9zIChsMykgdGllbmUgNTcgbml2ZWxlcyBkaXN0aW50b3MuIFZlYW1vcyBhIHRyYXbDqXMgZGUgYm94cGxvdHMgcGFyYWxlbG9zIGPDs21vIHNlIGNvbXBvcnRhbi4gCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTV9Cmxlbmd0aCh1bmlxdWUoZGF0b3NfcHJvcGVyYXRpJGwzKSkgIyA1NyBiYXJyaW9zCiMgYXJtbyBzY2F0dGVycGxvdCBkZSBwcmVjaW9zIGVuIG1pbGVzIGVuIGZ1bmNpw7NuIGRlIHN1cGVyZmljaWUgdG90YWwKZ2dwbG90KCBkYXRvc19wcm9wZXJhdGksIGFlcyh4ID0gZmN0X3Jlb3JkZXIobDMsIHByaWNlLCAuZGVzYyA9IFQpLCB5ID0gcHJpY2UvMTAwMCkpICsgCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43NSwgYWVzKGZpbGwgPSBsMykpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKSsKICBsYWJzKHkgPSAiUHJlY2lvcyBlbiBtaWxlcyIsIHggPSAiQmFycmlvcyIpICArCiAgZ2d0aXRsZSgiQm94cGxvdHMgZGUgcHJlY2lvcyBlbiBmdW5jacOzbiBkZSBsb3MgYmFycmlvcyIpKwogIHRoZW1lIChheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYWNlPSJpdGFsaWMiLCBjb2xvdXI9ImRhcmsgZ3JleSIsIHNpemUgPSA4LCBhbmdsZSA9IDkwKSkKYGBgCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NX0KIyBhcm1hbW9zIHNjYXR0ZXJwbG90IGRlIHByZWNpb3MgZW4gbWlsZXMgZW4gZnVuY2nDs24gZGUgc3VwZXJmaWNpZSB0b3RhbApnZ3Bsb3QoZGF0b3NfcHJvcGVyYXRpLCBhZXMoeCA9IGZjdF9yZW9yZGVyKGwzLCBwcmljZSwgLmRlc2MgPSBUKSwgeSA9IHByaWNlLzEwMDApKSArIAogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0gMC43NSwgYWVzKGZpbGwgPSBsMykpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKSsKICBsYWJzKHkgPSAiUHJlY2lvcyBlbiBtaWxlcyIsIHggPSAiQmFycmlvcyIpICArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMTIwMCkpICsKICBnZ3RpdGxlKCJCb3hwbG90cyBkZSBwcmVjaW9zIGVuIGZ1bmNpw7NuIGRlIGxvcyBiYXJyaW9zIikrCiAgdGhlbWUgKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhY2U9Iml0YWxpYyIsIGNvbG91cj0iZGFyayBncmV5Iiwgc2l6ZSA9IDgsIGFuZ2xlID0gOTApKQpgYGAKCkVuIGxvcyBib3hwbG90cyBwYXJhbGVsb3MgZGUgcHJlY2lvcyBwb3IgYmFycmlvcyBzZSBwdWVkZSB2ZXIgcXVlIGVudHJlIGxvcyBiYXJyaW9zIHF1ZSBwcmVzZW50YW4gbWF5b3JlcyBwcmVjaW9zIHNlIHViaWNhbjogUHVlcnRvIE1hZGVybyxMYXMgQ2HDsWl0YXMsIENhdGFsaW5hcywgUmVjb2xldGEgeSBCZWxncmFubywgbWllbnRyYXMgcXVlIFZpbGxhIFNvbGRhdGksIENvbnN0aXR1Y2nDs24sIFZpbGxhIGx1Z2FubyB5IGxhIEJvY2EgcHJlc2VudGFuIGxvcyBtZW5vcmVzIHByZWNpb3MgZGUgcHJvcGllZGFkZXMuIAoKUHJvYmVtb3MgKiphanVzdGFyIHVuIG1vZGVsbyBsaW5lYWwqKiBwYXJhIGVsIHByZWNpbyBlbiBmdW5jacOzbiBkZSBsYSBzdXBlcmZpY2llIHRvdGFsIHkgbG9zIGJhcnJpb3MuICAKCmBgYHtyfQojIGFqdXN0YW1vcyBlbCBtb2RlbG8KbW9kZWxvX3NjX2wzIDwtIGxtKHByaWNlIH4gc3VyZmFjZV9jb3ZlcmVkICsgbDMsIGRhdGEgPSB0cmFpbl9kYXRhKQp0aWR5X3NjX2wzIDwtIHRpZHkobW9kZWxvX3NjX2wzLCBjb25mLmludCA9IFRSVUUpCnRpZHlfc2NfbDMKYGBgCgpSIGN1YW5kbyBlZmVjdMO6YSBsYSByZWdyZXNpw7NuIGNhbGN1bGEgYXV0b23DoXRpY2FtZW50ZSBsYXMgdmFyaWFibGVzIGluZGljYWRvcmFzIChkdW1taWVzKSBwYXJhIGxhcyBjb3ZhcmlhYmxlcyBjYXRlZ8OzcmljYXMsIGVuIGdlbmVyYWwgc2Vnw7puIG9yZGVuIGFsZmFiw6l0aWNvLiBQb2RlbW9zIGNoZXF1ZWFyIGVsIG9yZGVuIHBhcmEgdmVyaWZpY2FyIGN1w6FsIGVzIGxhIGNhdGVnb3LDrWEgYmFzYWwuIEVuIGVzdGUgY2FzbywgbGEgY2F0ZWdvcsOtYSBkZSByZWZlcmVuY2lhIGNvcnJlc3BvbmRlIGFsIGJhcnJpbyBkZSAqQWJhc3RvKi4KCiMjIyMgU2lnbmlmaWNhZG8gZGUgbG9zIGNvZWZpY2llbnRlcyBlc3RpbWFkb3MKCsK/UXXDqSBzaWduaWZpY2FuIGxvcyBjb2VmaWNpZW50ZXMgZGUgZXN0YSB2YXJpYWJsZSBjYXRlZ8OzcmljYT8KCiogRXN0ZSBtb2RlbG8gcHJvcG9uZSBhanVzdGFyIHVuYSByZWN0YSBkaXN0aW50YSBwYXJhIGVsIHByZWNpbyAqKm1lZGlvKioKZGUgY2FkYSBwb2JsYWNpw7NuIGRlZmluaWRhIHBvciBlbCBiYXJyaW8sIHRvZGFzIGNvbiBpZ3VhbCBwZW5kaWVudGUgKGRlZmluaWRhIHBvciBsYSBzdXBlcmZpY2llKSwgeSA1NyBvcmRlbmFkYXMgYWwgb3JpZ2VuIGRpZmVyZW50ZXMsIHVuYSBwb3IgY2FkYSBiYXJyaW8uCgoqIFBvciBlamVtcGxvLCBlbGlnaWVuZG8gdW4gYmFycmlvIGRlIHByZWNpb3MgYWx0b3MsIHZlbW9zIHF1ZSAkXGJldGFfe0JlbGdyYW5vfSQgaW5kaWNhIGN1w6FudG8gc2UgaW5jcmVtZW50YSBlbCBwcmVjaW8gbWVkaW8gZGUgbGFzIHByb3BpZWRhZGVzIHBhcmEgYXF1ZWxsb3MgaW5tdWVibGVzIHViaWNhZG9zIGVuIEJlbGdyYW5vIHJlc3BlY3RvIGRlIGFxdWVsbG9zIHViaWNhZG9zIGVuIEFiYXN0byAoY2F0ZWdvcsOtYSBiYXNhbCksIGRhZGEgbGEgc3VwZXJmaWNpZS4KCiogQW5hbGl6YW5kbyB1biBiYXJyaW8gZGUgcHJlY2lvcyBiYWpvcywgJFxiZXRhX3tCb2NhfSQgaW5kaWNhIGN1w6FudG8gc2UgcmVkdWNlIGVsIHByZWNpbyBtZWRpbyBkZSBsYXMgcHJvcGllZGFkZXMgdWJpY2FkYXMgZW4gbGEgQm9jYSByZXNwZWN0byBkZSBhcXVlbGxhcyB1YmljYWRhcyBlbiBBYmFzdG8gKGNhdGVnb3LDrWEgYmFzYWwpLCBkYWRhIGxhIHN1cGVyZmljaWUuCgojIyBJbmZlcmVuY2lhIGRlIGxvcyAkzrJfayQgKHRlc3QgZGUgc2lnbmlmaWNhdGl2aWRhZCBpbmRpdmlkdWFsKQoKIyMjIyBUZXN0IHBhcmEgbGFzICTOsl9rJAoKUGFyYSBldmFsdWFyIGxhIHNpZ25pZmljYXRpdmRhZCBpbmRpdmlkdWFsIGRlIGNhZGEgdW5hIGRlIGxhcyB2YXJpYWJsZXMgc2UgYW5hbGl6YSBlbCB0ZXN0IHQgcXVlIGJ1c2NhIHByb2JhciBzaSBlbCBjb2VmaWNpZW50ZSBkZSByZWdyZXNpw7NuIGNvcnJlc3BvbmRpZW50ZSBhIGRpY2hhIHZhcmlhYmxlIGVzIGRpc3RpbnRvIGRlIDAgKGZpZ3VyYSBlbiBsYSB0YWJsYSByZXN1bWVuIGRlIHJlc3VsdGFkb3MgZGUgbGEgcmVncmVzacOzbikuCgpFcyBkZWNpciwgYnVzY2EgcHJvYmFyOiAgCgoqICRIXzA6IFxiZXRhX2sgPSAwJCAKCiogJEhfMTogXGJldGFfayDiiaAgMCQuIAoKKipNb2RlbG8gU3VwZXJmaWNpZSB5IEhhYml0YWNpb25lcyoqCgpgYGB7cn0Kb3B0aW9ucygic2NpcGVuIj0xKQp0aWR5X3NjX3IgJT4lCiAgc2VsZWN0KHRlcm0sIHN0YXRpc3RpYywgcC52YWx1ZSwgY29uZi5sb3csIGNvbmYuaGlnaCkKYGBgCgoqIEVuIGVzdGUgcHJpbWVyIG1vZGVsbyBzZSBvYnNlcnZhIHF1ZSB0YW50byBsYSB2YXJpYWJsZSAqc3VyZmFjZV90b3RhbCogY29tbyAqcm9vbXMqIHJlc3VsdGFuIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdmFzIHBhcmEgZXhwbGljYXIgZWwgcHJlY2lvIGRlIGxhcyBwcm9waWVkYWRlcyAocC12YWxvcmVzIDwgMC4wNSkuIAoKKiBBZGVtw6FzIGRlbCByZXN1bHRhZG8gZGVsIHRlc3QsIHBvZGVtb3MgYXByZWNpYXIgcXVlIGxvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSAoSUMpIGRlbCA5NSUgZGUgbGFzIHZhcmlhYmxlcyBkZSBzdXBlcmZpY2llIHkgaGFiaXRhY2lvbmVzIG5vIGNvbnRpZW5lbiBhbCAwLiAKCioqTW9kZWxvIFN1cGVyZmljaWUgeSBUaXBvIGRlIFByb3BpZWRhZCoqCgpgYGB7cn0KdGlkeV9zY19wdCAlPiUKICBzZWxlY3QodGVybSwgc3RhdGlzdGljLCBwLnZhbHVlLCBjb25mLmxvdywgY29uZi5oaWdoKSAKYGBgCgoqIEVuIGVzdGUgY2FzbyB0YW1iacOpbiBzZSBvYnNlcnZhIHF1ZSB0b2RhcyBsYXMgdmFyaWFibGVzIHJlc3VsdGFuIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdmFzIHBhcmEgZXhwbGljYXIgYWwgcHJlY2lvIGRlIGxhcyBwcm9waWVkYWRlcyAocC12YWxvcmVzIDwgMC4wNSkuIAoKKiBBZGVtw6FzIGRlbCByZXN1bHRhZG8gZGVsIHRlc3QsIHBvZGVtb3MgY29ycm9ib3JhciBxdWUgbG9zIGludGVydmFsb3MgZGUgY29uZmlhbnphIGRlbCA5NSUgcGFyYSBsb3MgY29lZmljaWVudGVzIGVzdGltYWRvcyBubyBjb250aWVuZW4gYWwgMCBlbiBuaW5ndW5vIGRlIGxvcyBjYXNvcy4gIAoKIyMjIyMgwr9Dw7NtbyBzZSBpbnRlcnByZXRhIGxhIHNpZ25pZmljYXRpdmlkYWQgZGUgbGFzIHZhcmlhYmxlcyBjYXRlZ8OzcmljYXM/CgoqIEVuIGVsIGNhc28gZGUgbGEgdmFyaWFibGUgdGlwbyBkZSBwcm9waWVkYWQsIGVzdGUgdGVzdCBwZXJtaXRlIGNoZXF1ZWFyIHNpIGxvcyB2YWxvcmVzIG1lZGlvcyBkZWwgcHJlY2lvIHNvbiBsb3MgbWlzbW9zIHBhcmEgbG9zIGRlcGFydGFtZW50b3MgbyBQSHMgcmVzcGVjdG8gZGUgbGFzIGNhc2FzIChjYXRlZ29yw61hIGJhc2FsKS4KCioqTW9kZWxvIFN1cGVyZmljaWUgVG90YWwgeSBCYXJyaW9zKiogCgpgYGB7cn0KdGlkeV9zY19sMyAlPiUKICBzZWxlY3QodGVybSwgc3RhdGlzdGljLCBwLnZhbHVlLCBjb25mLmxvdywgY29uZi5oaWdoKSAlPiUgCiAgYXJyYW5nZShwLnZhbHVlKQpgYGAKCiogRW4gZXN0ZSBtb2RlbG8gc2Ugb2JzZXJ2YSBxdWUgbWllbnRyYXMgbGEgdmFyaWFibGUgc3VwZXJmaWNpZSByZXN1bHRhIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdmEgcGFyYSBleHBsaWNhciBhbCBwcmVjaW8gKHAtdmFsb3JlcyA8IDAuMDUpLCBsYXMgY2F0ZWdvcsOtYXMgZGUgYmFycmlvcyBuby4gSGF5IGFsZ3Vub3MgcXVlIHJlc3VsdGFuIHNpZ25pZmljYXRpdm9zIHkgb3Ryb3Mgbm8uCgoqIEVzdG8gbWlzbW8gc2Ugb2JzZXJ2YSBhIHRyYXbDqXMgZGUgbG9zIGludGVydmFsb3MgZGUgY29uZmlhbnphIGRlbCA5NSUgZG9uZGUgYWxndW5vcyBjb250aWVuZW4gYWwgMCAocG9yIGVqLiBDYWJhbGxpdG8pIHkgb3Ryb3Mgbm8gKHBvciBlai4gUHVlcnRvIE1hZGVybykuICAKCiMjIyMjIMK/Q8OzbW8gc2UgaW50ZXJwcmV0YSBsYSBzaWduaWZpY2F0aXZpZGFkIGRlIGxhcyB2YXJpYWJsZXMgaW5kaWNhZG9yYXM/CgoqIEVzdGUgdGVzdCBwZXJtaXRlIGNoZXF1ZWFyIHNpIGxvcyB2YWxvcmVzIG1lZGlvcyBkZWwgcHJlY2lvIGRlIHByb3BpZWRhZGVzIHNvbiBsb3MgbWlzbW9zIGVuIGxvcyBkaXN0aW50b3MgYmFycmlvcyByZXNwZWN0byBkZSBsYSBjYXRlZ29yw61hIGJhc2FsLiBDYWJlIGRlc3RhY2FyLCBxdWUgZXN0b3MgcC12YWxvcmVzIHNvbiB2w6FsaWRvcyBwYXJhIGxhcyBjb21wYXJhY2lvbmVzIGluZGl2aWR1YWxlcyByZXNwZWN0byBkZSBsYSBjYXRlZ29yw61hIGJhc2FsIHBlcm8gbm8gYWJhcmNhbiB0b2RhcyBsYXMgY29tcGFyYWNpb25lcyBkZSBhIHBhcmVzLgoKKiBFcyBkZWNpciwgcXVlIGxvcyBuaXZlbGVzIG1lZGlvcyBkZSBwcmVjaW8gZGUgaW5tdWVibGVzIGVuIGxvcyBkaXN0aW50b3MgYmFycmlvcyBlbiBhbGd1bm9zIGNhc29zIGRpZmllcmVuIGRlIGxvcyBuaXZlbGVzIG1lZGlvcyBkZWwgQWJhc3RvIChiYXNhbCkgeSBlbiBvdHJvcyBuby4KCiogU2kgcXVlcmVtb3MgZXZhbHVhciBsYXMgdmFyaWFibGVzICpwcm9wZXJ0eV90eXBlKiBvICpsMyogZW4gc3UgY29uanVudG8sIGRlYmVtb3MgcmVjdXJyaXIgYSB1biB0ZXN0IEYuIAoKIyMgVGVzdCBGICh0ZXN0IGRlIHNpZ25pZmljYXRpdmlkYWQgZ2xvYmFsKQoKRWwgdGVzdCBjb25qdW50byBGICh5IHN1IGNvcnJlc3BvbmRpZW50ZSBwLXZhbG9yKSBwZXJtaXRlIG1lZGlyIGxhIHNpZ25pZmljYXRpdmlkYWQgY29uanVudGEgZGUgdW5hIHZhcmlhYmxlIGNhdGVnw7NyaWNhIHBhcmEgZXhwbGljYXIgbGEgcmVzcHVlc3RhLgoKVGVzdCBGIHNlIGNvbnN0cnV5ZSBwYXJhIHRlc3RlYXIgc2kgdmFyaW9zIHBhcsOhbWV0cm9zIHNvbiBjZXJvLCBlcyBkZWNpciwgcGFyYSBwcm9iYXIgbGFzIGhpcMOzdGVzaXM6CgoqICRIXzA6IM6yXzEgPSDOsl8yID0gwrcgwrcgwrcgPSDOsl97cOKIkjF9ID0gMCQKCiogJEhfMTokIG5vIHRvZG9zIGxvcyAkzrJfayQgKCRrID0gMSwgMiwuLi4sIHDiiJIxJCkgc29uIGlndWFsZXMgYSAwLiAKCkRpY2hvcyB0ZXN0cyBGIHNlIG9idGllbmVuIHBhcmEgY2FkYSB2YXJpYWJsZSBkZSBsYSB0YWJsYSBkZSBBTk9WQSBkZWwgbW9kZWxvLiBWZWFtb3MgcXXDqSBvY3VycmUgZW4gZXN0ZSBjYXNvLiAKCmBgYHtyfQojIE1vZGVsbyBTdXBlcmZpY2llIFRvdGFsIHkgVGlwbyBkZSBQcm9waWVkYWQKdGlkeShhbm92YShtb2RlbG9fc2NfcHQpKQpgYGAKCkxhIHRhYmxhIGRlIEFOT1ZBIG11ZXN0cmEgcXVlLCBzZWfDum4gZWwgcmVzdWx0YWRvIGRlbCB0ZXN0IEYsIGxhIHZhcmlhYmxlICpwcm9wZXJ0eV90eXBlKiBlbiBzdSBjb25qdW50byByZXN1bHRhIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdmEgcGFyYSBleHBsaWNhciBhbCBwcmVjaW8gKHAtdmFsb3IgPCAwLjA1KS4KCmBgYHtyfQojIE1vZGVsbyBTdXBlcmZpY2llIFRvdGFsIHkgQmFycmlvcwp0aWR5KGFub3ZhKG1vZGVsb19zY19sMykpCmBgYAoKTGEgdGFibGEgZGUgQU5PVkEgbXVlc3RyYSBxdWUsIHNlZ8O6biBlbCByZXN1bHRhZG8gZGVsIHRlc3QgRiwgbGEgdmFyaWFibGUgKmwzKiBlbiBzdSBjb25qdW50byByZXN1bHRhIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdmEgcGFyYSBleHBsaWNhciBhbCBwcmVjaW8gKHAtdmFsb3IgPCAwLjA1KS4gRXMgZGVjaXIsIHF1ZSBwZXNlIGEgcXVlIGFsZ3VuYXMgY2F0ZWdvcsOtYXMgZW4gc3UgY29tcGFyYWNpw7NuIGluZGl2aWR1YWwgY29uIGxhIGNhdGVnb3LDrWEgYmFzYWwgc2VhbiBwb2NvIHNpZ25pZmljYXRpdmFzLCBsYSB2YXJpYWJsZSBlbiBzdSBjb25qdW50byBzw60gcmVzdWx0YSBzaWduaWZpY2F0aXZhIHBhcmEgZWwgbW9kZWxvLiAKClNpIGVzdGUgdGVzdCBubyByZXN1bHRhcmEgc2lnbmlmaWNhdGl2bywgc3VlbGUgZGVzY2FydGFyc2UgbGEgdmFyaWFibGUgY2F0ZWfDs3JpY2EgZGUgZW50cmUgbGFzIGNvdmFyaWFibGVzIGRlIGludGVyw6lzLCB5IHNlIGxhIGV4Y2x1eWUgZGVsIG1vZGVsby4gUG9yIGVsIGNvbnRyYXJpbywgc2kgZXN0ZSB0ZXN0IHJlc3VsdGEgZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2bywgZW50b25jZXMgc3VlbGVuIG1pcmFyc2UgY29uIG3DoXMgZGV0YWxsZSBjdcOhbGVzIGRlIGxhcyBjb21wYXJhY2lvbmVzIGVudHJlIGdydXBvcyBzb24gZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2YXMsIHBhcmEgcHJvcG9yY2lvbmFyIHVuIG1lam9yIGFuw6FsaXNpcyBkZSBsb3MgZGF0b3MuIAoKT3RyYSBhbHRlcm5hdGl2YSBzZXLDrWEgZ2VuZXJhciB1bmEgbnVldmEgdmFyaWFibGUgY29uIG1lbm9yIG7Dum1lcm8gZGUgdmFyaWFibGVzIGNhdGVnw7NyaWNhcyBxdWUgc2VhbiBzaWduaWZpY2F0aXZhcywgc2luIHBlcmRlciBjYXBhY2lkYWQgZXhwbGljYXRpdmEuIFBvciBlamVtcGxvLCBzZSBwb2Ryw61hIGFybWFyIHVuYSBudWV2YSB2YXJpYWJsZSBxdWUgYWdydXBlIGxvcyBiYXJyaW9zLiAKCiMjIyBHZW5lcmFjacOzbiBkZSBudWV2YSB2YXJpYmxlIGB0aXBvX2JhcnJpb2AKCiogU2UgY3JlYSB1bmEgbnVldmEgdmFyaWFibGUgYHRpcG9fYmFycmlvYCBxdWUgY2xhc2lmaWNhIGEgbG9zIGJhcnJpb3Mgc2Vnw7puIGVsIHByZWNpbyBwb3IgbWV0cm8gY3VhZHJhZG8gcHJvbWVkaW8gZGUgbGFzIHByb3BpZWRhZGVzIGVuIGVsbG9zLCBkZSBhY3VlcmRvIGEgcHJlY2lvcyBhbHRvcywgbWVkaW9zIHkgYmFqb3MuIAoKKiBQYXJhIGVsbG8sIHByaW1lcm8gc2UgZ2VuZXJhIHVuYSBudWV2YSB2YXJpYWJsZSBkZSBwcmVjaW9zIHBvciBtZXRybyBjdWFkcmFkbyBgcHhtMmAgcGFyYSBwb2RlciBnZW5lcmFyIHVuYSBjbGFzaWZpY2FjacOzbiBkZWwgYmFycmlvIGVuIGJhc2UgYSB1bmEgZGVjaXNpw7NuIGRlIG5lZ29jaW8gKGxvIHF1ZSB2YWxlIGVuIHByb21lZGlvIGVsIG1ldHJvIGN1YWRyYWRvIGVuIGNhZGEgYmFycmlvKS4gCgpgYGB7cn0KIyBDcmVhbW9zIHVuYSBudWV2YSB2YXJpYWJsZSAgZGUgcHJlY2lvcyBwb3IgbWV0cm8gY3VhZHJhZG8KdHJhaW5fZGF0YSA9IHRyYWluX2RhdGEgJT4lIAogIG11dGF0ZShweG0yID0gcm91bmQocHJpY2Uvc3VyZmFjZV90b3RhbCwwKSkKIyBBcm1hbW9zIHVuIGRhdGFmcmFtZSBxdWUgbXVlc3RyZSBsb3MgcHJvbWVkaW9zIGRlIHB4bTIgZW4gY2FkYSBiYXJyaW8KQVZHX3B4bTJfbDMgPSB0cmFpbl9kYXRhICU+JSAKICBncm91cF9ieShsMykgJT4lCiAgc3VtbWFyaXNlKEFWR19weG0yX2wzID0gbWVhbihweG0yKSkKQVZHX3B4bTJfbDMKYGBgCgpPYnNlcnZlbW9zIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIHByZWNpb3MgcHJvbWVkaW8gcG9yIG0yLiAKCmBgYHtyfQojIGJveHBsb3QgZGUgcHJlY2lvcyBwb3IgbWV0cm8gY3VhZHJhZG8KZ2dwbG90KGRhdGEgPSBBVkdfcHhtMl9sMywgYWVzKHggPSBBVkdfcHhtMl9sMykpICsgCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43NSkgKwogIGxhYnModGl0bGUgPSAiQm94cGxvdCBkZSBwcmVjaW9zIHByb21lZGlvIGRlIGJhcnJpb3MgcG9yIG0yIikgKwogIGxhYnMoeCA9ICJQcmVjaW9zIHByb21lZGlvIGRlIGJhcnJpb3MgcG9yIG0yIikKYGBgCkFwbGljYXJlbW9zIGVsIHNpZ3VpZW50ZSBjcml0ZXJpbyBwYXJhIGFncnVwYXIgbG9zIGJhcnJpb3MgZW46CgoqICoqcHJlY2lvX2Jham8qKjogIGJhcnJpb3MgY3V5byBwcmVjaW8gcHJvbWVkaW8gcG9yIG0yIHNlYSBtZW5vciBhbCBRMQoqICoqcHJlY2lvX21lZGlvKio6IGJhcnJpb3MgY3V5byBwcmVjaW8gcHJvbWVkaW8gc2UgZW5jdWVudHJlIGVuIGVsIFJJCiogKipwcmVjaW9fYWx0byoqOiBiYXJyaW9zIGN1eW8gcHJlY2lvIHByb21lZGlvIHBvciBtMiBzZWEgbWF5b3IgYWwgUTMKCmBgYHtyfQojIGFybWFtb3MgbnVldmEgdmFyaWFibGUgc2lndWllbmRvIHRhbGVzIGNyaXRlcmlvcwpBVkdfcHhtMl9sMyA9IEFWR19weG0yX2wzICU+JQogIG11dGF0ZSh0aXBvX2JhcnJpbyA9IGNhc2Vfd2hlbigKICAgIEFWR19weG0yX2wzIDwgcXVhbnRpbGUoQVZHX3B4bTJfbDMpWzJdIH4gInByZWNpb19iYWpvIiwKICAgIEFWR19weG0yX2wzID49IHF1YW50aWxlKEFWR19weG0yX2wzKVsyXSAmIEFWR19weG0yX2wzIDwgcXVhbnRpbGUoQVZHX3B4bTJfbDMpWzRdIH4gInByZWNpb19tZWRpbyIsCiAgICBUUlVFIH4gInByZWNpb19hbHRvIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICkKd3JpdGUuY3N2KEFWR19weG0yX2wzLCAnQVZHX3B4bTJfbDMuY3N2JykKIyB3cml0ZV9jc3YoQVZHX3B4bTJfbDMsICdBVkdfcHhtMl9sM18uY3N2JykKIyB1bmltb3MgZXN0YSBjbGFzaWZpY2FjacOzbiBhbCBkYXRhc2V0IG9yaWdpbmFsCnRyYWluX2RhdGEgPSB0cmFpbl9kYXRhICU+JSBsZWZ0X2pvaW4oQVZHX3B4bTJfbDMsIGJ5ID0gJ2wzJykgCmhlYWQodHJhaW5fZGF0YSkKYGBgCgpBanVzdGFtb3MgZWwgbW9kZWxvIGNvbiBsYSBudWV2YSB2YXJpYWJsZSB0aXBvX2JhcnJpbyBlbiB2ZXogZGUgbDMuIAoKYGBge3J9CiMgYWp1c3RhbW9zIGVsIG1vZGVsbwptb2RlbG9fc2NfdGIgPC0gbG0ocHJpY2UgfiBzdXJmYWNlX2NvdmVyZWQgKyB0aXBvX2JhcnJpbywgZGF0YSA9IHRyYWluX2RhdGEpCnRpZHlfc2NfdGIgPC0gdGlkeShtb2RlbG9fc2NfdGIsIGNvbmYuaW50ID0gVFJVRSkKdGlkeV9zY190YgpgYGAKCsK/UXXDqSBwYXNhIGFob3JhIGNvbiBsYSBzaWduaWZpY2F0aXZpZGFkIGRlIGxvcyBwcmVkaWN0b3Jlcz8KCiMjIyBDb2xpbmVhbGlkYWQgZGUgbG9zIFByZWRpY3RvcmVzCgpDdWFuZG8gbGFzIHZhcmlhYmxlcyBwcmVkaWN0b3JhcyBlc3TDoW4gY29ycmVsYWNpb25hZGFzIGVudHJlIHPDrSwgZGVjaW1vcyBxdWUgZXhpc3RlIGludGVyY29ycmVsYWNpw7NuIG8gbXVsdGljb2xpbmVhbGlkYWQuIAoKwr9RdcOpIHBhc2EgZW4gbnVlc3RybyBkYXRhc2V0IGNvbiBsYSBzdXBlcmZpY2llIGN1YmllcnRhIHkgZGVzY3ViaWVydGE/CgpgYGB7cn0KY29yKHRyYWluX2RhdGEkc3VyZmFjZV90b3RhbCwgdHJhaW5fZGF0YSRzdXJmYWNlX2NvdmVyZWQpCmBgYApDb21vIHlhIGhhYsOtYW1vcyB2aXN0byBlbiBlbCBncsOhZmljbyBnZ3BhaXJzIGluaWNpYWwsIGVzdGFzIHZhcmlhYmxlcyB0aWVuZW4gYWx0YSBjb3JyZWxhY2nDs24uIFZlYW1vcyBxdcOpIG9jdXJyZSBjb24gbG9zIGNvZWZpY2llbnRlcyBkZSBhbWJhcyB2YXJpYWJsZXMgYWwgYXJtYXIgZGlzdGludG9zIG1vZGVsb3MgbcO6bHRpcGxlcyBxdWUgbGFzIGluY2x1eWFuLiAKCkFybWFtb3MgdW4gKiptb2RlbG8gY29uIHN1cGVyZmljaWUgdG90YWwsIHN1cGVyZmljaWUgY3ViaWVydGEsIGhhYml0YWNpb25lcyB5IHRpcG8gZGUgcHJvcGllZGFkKiouIAoKYGBge3J9Cm1vZGVsb19zdHNjX3JfcHQgPC0gbG0ocHJpY2UgfiBzdXJmYWNlX3RvdGFsICsgc3VyZmFjZV9jb3ZlcmVkICsgcm9vbXMgKyBwcm9wZXJ0eV90eXBlLCBkYXRhID0gdHJhaW5fZGF0YSkKdGlkeShtb2RlbG9fc3RzY19yX3B0KQpgYGAKCkFybWFtb3MgdW4gKiptb2RlbG8gY29uIHN1cGVyZmljaWUgdG90YWwgeSBjdWJpZXJ0YSoqLiAKCmBgYHtyfQptb2RlbG9fc3RzYyA8LSBsbShwcmljZSB+IHN1cmZhY2VfdG90YWwgKyBzdXJmYWNlX2NvdmVyZWQsIGRhdGEgPSB0cmFpbl9kYXRhKQp0aWR5KG1vZGVsb19zdHNjKQpgYGAKCkFybWFtb3MgdW4gKiptb2RlbG8gY29uIHN1cGVyZmljaWUgdG90YWwsIGhhYml0YWNpb25lcyB5IHRpcG8gZGUgcHJvcGllZGFkKiogcGVybyBzaW4gY29udGVtcGxhciBzdXBlcmZpY2llIGN1YmllcnRhLiAKCmBgYHtyfQptb2RlbG9fc3Rfcl9wdCA8LSBsbShwcmljZSB+IHN1cmZhY2VfdG90YWwgKyByb29tcyArIHByb3BlcnR5X3R5cGUsIGRhdGEgPSB0cmFpbl9kYXRhKQp0aWR5KG1vZGVsb19zdF9yX3B0KQpgYGAKCiMjIyMjIMK/UXXDqSBkaWZlcmVuY2lhcyBlbmN1ZW50cmFuIGNvbiBsb3MgY29lZmljaWVudGVzIGRlIHN1cGVyZmljaWUgdG90YWwgeSBjdWJpZXJ0YSBlbiBsb3MgMyBtb2RlbG9zPwoKKiBMb3MgY29lZmljaWVudGVzIGRlIHJlZ3Jlc2nDs24gZXN0aW1hZG9zIHNlIG1vZGlmaWNhbiBzdXN0YW5jaWFsbWVudGUgY3VhbmRvIGFncmVnYW1vcyBvIHF1aXRhbW9zIHZhcmlhYmxlcyBkZWwgbW9kZWxvLiBFbiBlbCBtb2RlbG8gcXVlIHRpZW5lIGxhcyA0IHZhcmlhYmxlcyB2cyBlbCBxdWUgc29sbyB0aWVuZSBsYXMgc3VwZXJmaWNpZXMgY3ViaWVydGEgeSB0b3RhbCBlbCBiZXRhIGVzdGltYWRvIGRlIGxhIHN1cGVyZmljaWUgdG90YWwgY2FtYmlhIGRlIDkxOCBhIDQxMiB5IGxhIGN1YmllcnRhIGRlIDI0MjEgYSAyNTE2LiAKCiogTG9zIGVycm9yZXMgZXN0w6FuZGFyZXMgZGUgbG9zIGVzdGltYWRvcmVzIGRlIGxvcyBjb2VmaWNpZW50ZXMgYXVtZW50YW4gZXNww7pyZWFtZW50ZSBjdWFuZG8gc2UgaW5jbHV5ZW4gY292YXJpYWJsZXMgbXV5IGNvcnJlbGFjaW9uYWRhcy4gU2UgaW5mbGEgbGEgdmFyaWFuemEgZXN0aW1hZGEgZGUgbG9zIGVzdGltYWRvcmVzLiBFbiBudWVzdHJvIGNhc286IGVsIGVycm9yIGVzdMOhbmRhciBkZSBsYSB2YXJpYWJsZSBzdXBlcmZpY2llIHRvdGFsIGVuIGVsIHByaW1lciBtb2RlbG8gZG9uZGUgZXN0w6EgaW5jbHVpZGEgbGEgc3VwZXJmaWNpZSBjdWJpZXJ0YSBlcyBkZSBhbHJlZGVkb3IgZGUgOTE4LCBtaWVudHJhcyBxdWUgZW4gZWwgbW9kZWxvIMO6bHRpbW8gcXVlIHNlIGV4Y2x1eWUgZGljaGEgdmFyaWFibGUgZXMgZGUgMjU2MC4KClZlYW1vcyBxdcOpIG9jdXJyZSBzaSBlbiB2ZXogZGUgdXNhciBsYSBzdXBlcmZpY2llIHRvdGFsIGVuIGVsIG1vZGVsbyDDumx0aW1vIHVzYW1vcyBsYSBzdXBlcmZpY2llIGN1YmllcnRhLgoKYGBge3J9Cm1vZGVsb19zY19yX3B0IDwtIGxtKHByaWNlIH4gc3VyZmFjZV9jb3ZlcmVkICsgcm9vbXMgKyBwcm9wZXJ0eV90eXBlLCBkYXRhID0gdHJhaW5fZGF0YSkKdGlkeShtb2RlbG9fc2Nfcl9wdCkKYGBgCgpPYnNlcnZhbW9zIHF1ZSBvdHJhIHZleiBjYW1iaWEgZWwgdmFsb3IgZGVsIGVzdGltYWRvci4gCgpMb3MgY29lZmljaWVudGVzIHB1ZWRlbiBzZXIgbm8gc2lnbmlmaWNhdGl2b3MgYcO6biBjdWFuZG8gZXhpc3RhIHVuYSBhc29jaWFjacOzbiB2ZXJkYWRlcmEgZW50cmUgbGEgdmFyaWFibGUgZGUgcmVzcHVlc3RhIHkgZWwgY29uanVudG8gZGUgcmVncmVzb3JhcyBjdWFuZG8gYXJtYW1vcyB1biBtb2RlbG8gY29uIG11bHRpY29saW5lYWxpZGFkIGRlIHZhcmlhYmxlcyByZWdyZXNvcmFzLiAKCj4gSGF5IHF1ZSB0ZW5lciBjdWlkYWRvIGNvbiBsYSBjb2xpbmVhbGlkYWQgZGUgbG9zIHByZWRpY3RvcmVzIHBhcmEgbm8gdGVuZXIgcHJvYmxlbWFzIGNvbiBsYSBpbnRlcnByZXRhY2nDs24gZGUgbG9zIGNvZWZpY2llbnRlcyBkZWwgbW9kZWxvIGxpbmVhbCB5IHF1ZSBubyBhdW1lbnRlbiBlc3DDunJlYW1lbnRlIGxhIHZhcmlhbnphIGVzdGltYWRhIGRlIGxvcyBlc3RpbWFkb3Jlcy4gCgojIyMgT2JzZXJ2YWNpb25lcyBzb2JyZSBsYSBpbnRlcnByZXRhY2nDs24gZGUgbG9zIGNvZWZpY2llbnRlcwoKKipNb2RlbG8gY29uIHN1cGVyZmljaWVzIHRvdGFsIHkgY3ViaWVydGEqKgoKTGEgaW50ZXJwcmV0YWNpw7NuIGRlIGxvcyBjb2VmaWNpZW50ZXMgZXN0aW1hZG9zIHNlcsOtYToKCiogJFxoYXR7XGJldGFfe3N1cmZhY2VcX3RvdGFsfX0kIGluZGljYSBxdWUgcG9yIGNhZGEgbTIgYWRpY2lvbmFsIGRlIHN1cGVyZmljaWUgdG90YWwgZWwgcHJlY2lvIGVzcGVyYWRvIGF1bWVudGEgZW4gNDEyIGTDs2xhcmVzLCBkYWRhIGxhIHN1cGVyZmljaWUgY3ViaWVydGEuCgoqICRcaGF0e1xiZXRhX3tzdXJmYWNlXF9jb3ZlcmVkfX0kIGluZGljYSBxdWUgcG9yIGNhZGEgbTIgYWRpY2lvbmFsIGRlIHN1cGVyZmljaWUgY3ViaWVydGEgZWwgcHJlY2lvIGVzcGVyYWRvIGF1bWVudGEgZW4gMjUxNiBkw7NsYXJlcywgZGFkYSBsYSBzdXBlcmZpY2llIHRvdGFsLgoKUmVzcGVjdG8gYSBsYSBzZWd1bmRhIGludGVycHJldGFjacOzbiBhbGd1aWVuIHBvZHLDrWEgb2JqZXRhciBsbyBzaWd1aWVudGU6Cgokc3VyZmFjZVxfdG90YWwgPSBzdWZhY2VcX2NvdmVyZWQgKyBzdWZhY2VcX3VuY292ZXJlZCQKCkVudG9uY2VzLCBzaSBhdW1lbnRvIGVuIHVuIG0yIGxhIHN1cGVyZmljaWUgY3ViaWVydGEgbm8gcHVlZG8gc29zdGVuZXIgcXVlIHZhcmlhYmxlIHN1cGVyZmljaWUgdG90YWwgc2UgbWFudGllbmUgY29uc3RhbnRlLgoKwr9FcyBlc3RhIG9ic2VydmFjacOzbiBjb3JyZWN0YT8KCkVsIGNvZWZpY2llbnRlIGRlICRcaGF0e1xiZXRhX3tzdXJmYWNlXF90b3RhbH19JCBlbiByZWFsaWRhZCBub3MgcGVybWl0ZSBldmFsdWFyIGN1YWwgZXMgZWwgZWZlY3RvIGVuIGVsIHByZWNpbyBlc3BlcmFkbyBkZSB1biBtMiBtw6FzIGRlIHN1cGVyZmljaWUgZGVzY3ViaWVydGEgcGFyYSBpZ3VhbCBjYW50aWRhZCBkZSBtMiBkZSBzdXBlcmZpY2llIGN1YmllcnRhLiBFcyBkZWNpciwgbG8gcXVlIGNhbWJpYSBlcyBsYSBpbnRlcnByZXRhY2nDs24gZW4gZXN0ZSBjYXNvIGRlIGRpY2hvIGNvZWZpY2llbnRlLgoKUG9yIGVqZW1wbG8sIHNpIGV4aXN0ZW4gZG9zIHByb3BpZWRhZGVzIGRlIDUwbTIgZGUgc3VwZXJmaWNpZSB0b3RhbCB5IGxhIHByb3BpZWRhZCBBIHRpZW5lIDUgbTIgZGUgc3VwZXJmaWNpZSBkZXNjdWJpZXJ0YSB5IGxhIHByb3BpZWRhZCBCIDQgbTIsIG51ZXN0cm8gbW9kZWxvIG5vcyBpbmRpY2EgcXVlIGVsIHByZWNpbyBwcmVkaWNobyBwYXJhIGxhIHByb3BpZWRhZCBCIHZhIGEgc2VyIDQxMiBkw7NsYXJlcyBtZW5vciBhbCBwcmVjaW8gZGUgbGEgcHJvcGllZGFkIEEuCgoqKk1vZGVsbyBzdXBlcmZpY2llcyBjdWJpZXJ0YSB5IGRlc2N1YmllcnRhKioKClNpIHF1aXNpZXJhbW9zIHBvZGVyIHNlcGFyYXIgZWwgZWZlY3RvIGRlIGxhIHN1cGVyZmljaWUgY3ViaWVydGEgeSBkZXNjdWJpZXJ0YSBkZWJlcsOtYW1vcyBjcmVhciB1bmEgdmFyaWFibGUgbnVldmEgcXVlIHNlYToKCiRzdXJmYWNlXF91bmNvdmVyZWQgPSBzdWZhY2VcX3RvdGFsICsgc3VmYWNlXF9jb3ZlcmVkJAoKQWhvcmEgbnVlc3RybyBtb2RlbG8gZXM6CgokRShwcmVjaW98Li4uKSA9IFxiZXRhXzAgKyBcYmV0YV97c2N9c3VyZmFjZVxfY292ZXJlZCArIFxiZXRhX3tzdX1zdXJmYWNlXF91bmNvdmVyZWQkCgpQYXJhIGVsbG8gY3JlYW1vcyB1bmEgbnVldmEgdmFyaWFibGUgZGUgc3VwZXJmaWNpZSBkZXNjdWJpZXJ0YSBxdWUgc2VhIHJlc3VsdGFkbyBkZSBsYSByZXN0YSBlbnRyZSBzdXBlcmZpY2llIHRvdGFsIHkgY3ViaWVydGEuIAoKYGBge3J9CmRmMiA9IHRyYWluX2RhdGEgJT4lCiAgbXV0YXRlKHN1cmZhY2VfdW5jb3ZlcmVkID0gc3VyZmFjZV90b3RhbCAtIHN1cmZhY2VfY292ZXJlZCkKYGBgCgpDb25zdHJ1aW1vcyBlbCBtb2RlbG8gbGluZWFsIHF1ZSBwbGFudGVhbW9zIAoKYGBge3J9CnRpZHkobG0ocHJpY2UgfiBzdXJmYWNlX2NvdmVyZWQgKyBzdXJmYWNlX3VuY292ZXJlZCwgZGF0YSA9IGRmMikpCmBgYAoKTGEgaW50ZXJwcmV0YWNpw7NuIGRlIGxvcyBjb2VmaWNpZW50ZXMgZXN0aW1hZG9zIGVzOgoKKiAkXGhhdHtcYmV0YV97c3VmYWNlXF9jb3ZlcmVkfX0kIGluZGljYSBxdWUgcG9yIGNhZGEgbTIgYWRpY2lvbmFsIGRlIHN1cGVyZmljaWUgY3ViaWVydGEgZWwgcHJlY2lvICoqZXNwZXJhZG8qKiBkZSBsYXMgcHJvcGllZGFkZXMgYXVtZW50YSBlbiAyLjkyOSBkw7NsYXJlcywgZGFkYSBsYSBzdXBlcmZpY2llIGRlc2N1YmllcnRhLgoKKiAkXGhhdHtcYmV0YV97c3VmYWNlXF91bmNvdmVyZWR9fSQgaW5kaWNhIHF1ZSBwb3IgY2FkYSBtMiBhZGljaW9uYWwgZGUgc3VwZXJmaWNpZSBkZXNjdWJpZXJ0YSBlbCBwcmVjaW8gKiplc3BlcmFkbyoqIGF1bWVudGEgNDEyIGTDs2xhcmVzLCBkYWRhIGxhIHN1cGVyZmljaWUgY3ViaWVydGEuCgpFbiBlc3RlIGNhc28gbGEgcmVncmVzacOzbiBheXVkYSBhIGVudGVuZGVyIGPDs21vIGFmZWN0YSBsYSBzdXBlcmZpY2llIGN1YmllcnRhIHkgZGVzY3ViaWVydGEgYWwgcHJlY2lvIGRlbCBpbm11ZWJsZS4gRXMgZGVjaXIsIGN1w6FudG8gYXVtZW50YSBlbCBwcmVjaW8gbWVkaW8gdW4gbTIgYWRpY2lvbmFsIGRlIHN1cGVyZmljaWUgY3ViaWVydGEsIGRhZGEgbGEgc3VwZXJmaWNpZSBkZXNjdWJpZXJ0YSwgeSBjdcOhbnRvIGF1bWVudGEgZWwgcHJlY2lvIHByb21lZGlvIHVuIG0yIGFkaWNpb25hbCBkZSBzdXBlcmZpY2llIGRlc2N1YmllcnRhLCBkYWRhIGxhIHN1cGVyZmljaWUgY3ViaWVydGEuIAoKVm9sdmVtb3MgYSBvYnNlcnZhciBxdWUgZWwgcCB2YWxvciBhc29jaWFkbyBhICRcYmV0YV8yJCBpbmRpY2EgcXVlIG5vIHNlIHB1ZWRlIHJlY2hhemFyIGxhIGhpcG90ZXNpcyBudWxhIGRlbCB0ZXN0IGRlIHNpZ25pZmljYXRpdmlkYWQgaW5kaXZpZHVhbC4=
LS0tDQp0aXRsZTogIlJlZ3Jlc2nDs24gTGluZWFsIE3Dumx0aXBsZSBJIg0KYXV0aG9yOiAiSnVhbiBCYXJyaW9sYSB5IFNvZsOtYSBQZXJpbmkiDQpkYXRlOiAiMjUgZGUgU2VwdGllbWJyZSBkZSAyMDIxIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRoZW1lOiBzcGFjZWxhYg0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCi0tLQ0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KZGl2Lm1haW4tY29udGFpbmVyIHsNCiAgbWF4LXdpZHRoOiAxNjAwcHg7DQogIG1hcmdpbi1sZWZ0OiBhdXRvOw0KICBtYXJnaW4tcmlnaHQ6IGF1dG87DQp9DQo8L3N0eWxlPg0KICANCiMjIFBsYW50ZW8gZGVsIHByb2JsZW1hDQoNCk51ZXN0cm8gb2JqZXRpdm8gZXMgY3JlYXIgdW4gbW9kZWxvIGxpbmVhbCBtw7psdGlwbGUgcGFyYSBleHBsaWNhciBlbCBwcmVjaW8gZGUgdmVudGEgZW4gZMOzbGFyZXMgZGUgbGFzIHByb3BpZWRhZGVzIGVuIENhcGl0YWwgRmVkZXJhbCByZXBvcnRhZGFzIHBvciBsYSBlbXByZXNhIFtQcm9wZXJhdGkgQXJnZW50aW5hXShodHRwczovL3d3dy5wcm9wZXJhdGkuY29tLmFyLykuIA0KDQpWYW1vcyBhIHV0aWxpemFyIGRhdG9zIGRlbCAyMDE5IHBhcmEgbm8gaW5jb3Jwb3JhciBjb21wb3J0YW1pZW50b3MgYXTDrXBpY29zIG9jYXNpb25hZG9zIHBvciBsYSBwYW5kZW1pYSBkZWwgQ09WSUQtMTkuDQoNCk51ZXN0cmEgaWRlYSBzdWJ5YWNlbnRlIGRlIGPDs21vIHNlIHB1ZWRlIGV4cGxpY2FyIGVsIHByZWNpbyBlczoNCg0KJHByZWNpbyA9IFxiZXRhXzAgK1xiZXRhXzFYXzErXGJldGFfMlhfMisuLi4rXGVwc2lsb24kDQoNCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh0aWR5bW9kZWxzKQ0KbGlicmFyeShyc2FtcGxlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShHR2FsbHkpDQpgYGANCg0KIyMgTGV2YW50YW1vcyBEYXRhc2V0DQoNClZhbW9zIGEgdHJhYmFqYXIgY29uIHVuIHN1YmNvbmp1bnRvIGRlIGRhdG9zIHF1ZSBzdXJnacOzIGRlIHVuIHRyYWJham8gZGUgbGltcGllemEgeSB0cmF0YW1pZW50byBkZSBvdXRsaWVycyBxdWUgc2UgcHVlZGUgY29uc3VsdGFyIGVuIGVsIG5vdGVib29rIGRlIFByZXByb2Nlc2FtaWVudG8gRGF0YXNldCBQcm9wZXJhdGksIGNvcnJlc3BvbmRpZW50ZSBhIHByZWNpb3MgZGUgcHJvcGllZGFkZXMgZW4gQ2FwaXRhbCBGZWRlcmFsLCBjdXlvIHByZWNpbyBlc3TDoSBleHByZXNhZG8gZW4gZG9sYXJlcyAoVVNEKSwgZWwgdGlwbyBkZSBwcm9waWVkYWQgY29ycmVzcG9uZGUgYSBEZXBhcnRhbWVudG8sIFBIIG8gQ2FzYSwgeSBlbCB0aXBvIGRlIG9wZXJhY2lvbiBzZWEgVmVudGEuIA0KDQpgYGB7ciwgbWVzc2FnZT1GfQ0KZGF0b3NfcHJvcGVyYXRpIDwtIHJlYWQuY3N2KCJwcm9wZXJhdGlfcHJlcHJvY2VzYWRvLmNzdiIpDQpnbGltcHNlKGRhdG9zX3Byb3BlcmF0aSkNCmBgYA0KDQpMYSBsaW1waWV6YSBjb25zaXN0acOzIGVuOiBlbGltaW5hciBsYSB2YXJpYWJsZSBiZWRyb29tcyBwb3IgcmVnaXN0cmFyIGdyYW4gcHJlc2VuY2lhIGRlIGZhbHRhbnRlcyAoNDAlKSB5IGNvcnJlbGFjacOzbiBwb3NpdGl2YSBmdWVydGUgY29uIGxhIHZhcmlhYmxlIHJvb21zICgwLjk3KSwgZWxpbWluYXIgbG9zIHJlZ2lzdHJvcyBjb24gZmFsdGFudGVzLCBkZXNjYXJ0YXIgcmVnaXN0cm9zIGRvbmRlIGxhIHN1cGVyZmljaWUgdG90YWwgcmVzdWx0YSBpbmZlcmlvciBhIGxhIGN1YmllcnRhLCBwb3IgdHJhdGFyc2UgcHJvYmFibGVtZW50ZSBkZSBhbGfDum4gZXJyb3IgZGUgY2FyZ2EuIFBvciDDumx0aW1vLCBzZSByZWFsaXrDsyB1biB0cmF0YW1pZW50byBkZSBsb3Mgb3V0bGllcnMsIGVtcGxlYW5kbyBsYXMgdMOpY25pY2FzIHZpc3RhcyBlbiBsYSBjbGFzZSAzLCBxdWVkYW5kbyBjb21vIHJlc3VsdGFkbyB1biBkYXRhc2V0IGRlIDQ5LjgzNSBvYnNlcnZhY2lvbmVzIHkgOSBjb2x1bW5hcywgY29uIGVsIHF1ZSB0cmFiYWphcmVtb3MgYSBjb250aW51YWNpw7NuLiANCg0KIyMjIFNlbGVjY2lvbmFtb3MgdmFyaWFibGVzIGRlIGludGVyw6lzDQoNCkVuIGVzdGUgY2FzbyB5YSBlc3TDoW4gcHJlc2VsZWNjaW9uYWRhcyA5IHZhcmlhYmxlczoNCg0KLSAqaWQqOiBpZGVudGlmaWNhY2lvbi4NCi0gKmwzKjogYmFycmlvLg0KLSAqcm9vbXMqOiBucm8gZGUgaGFiaXRhY2lvbmVzLg0KLSAqYmF0aHJvb21zKjogbnJvIGRlIGJhw7Fvcw0KLSAqc3VyZmFjZV90b3RhbCo6IHN1cGVyZmljaWUgdG90YWwgZW4gbTINCi0gKnN1cmZhY2VfY292ZXJlZCo6IHN1cGVyZmljaWUgY3ViaWVydGEgZW4gbTINCi0gKnByaWNlKjogcHJlY2lvICh2YXJpYWJsZSBhIHByZWRlY2lyKSBlbiBkw7NsYXJlcw0KLSAqcHJvcGVydHlfdHlwZSo6IHRpcG8gZGUgcHJvcGllZGFkIChEZXBhcnRhbWVudG8sIFBIIG8gQ2FzYSkNCi0gKnByZWNpb19lbl9taWxlcyo6IHZhcmlhYmxlIGNyZWFkYSBwb3Igbm9zb3Ryb3MgcGFyYSBncmFmaWNhciANCg0KYGBge3J9DQpkYXRvc19wcm9wZXJhdGkgJT4lDQogIGhlYWQoKQ0KYGBgDQoNClZlYW1vcyBjw7NtbyBlcyBsYSBjb3JyZWxhY2nDs24gZW50cmUgbGFzIHZhcmlhYmxlcyBudW3DqXJpY2FzLiANCg0KYGBge3IsIHByb2dyZXNzPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCAgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTh9DQojIGdyYWZpY2Ftb3MgY29uIGdncGFpcnMgY29sb3JlYW5kbyBwb3IgcHJvcGVydHkgdHlwZQ0KZyA8LSBnZ3BhaXJzKGRhdG9zX3Byb3BlcmF0aSAlPiUgc2VsZWN0KC1jKGlkLGwzKSksIGFlcyhjb2xvciA9IHByb3BlcnR5X3R5cGUpLCANCiAgICAgICAgICB1cHBlciA9IGxpc3QoY29udGludW91cyA9IHdyYXAoImNvciIsIHNpemUgPSAzLCBoanVzdD0wLjUpKSwgbGVnZW5kID0gMjUsIHByb2dyZXNzPUZBTFNFKSArIA0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKyANCiAgdGhlbWVfYncoKQ0KIyBoYWNlbW9zIHVuIGxvb3AgcGFyYSBjYW1iaWFyIGxvcyBjb2xvcmVzIGRlbCBncsOhZmljbw0KZm9yKGkgaW4gMTpnJG5yb3cpIHsNCiAgZm9yKGogaW4gMTpnJG5jb2wpew0KICAgIGdbaSxqXSA8LSBnW2ksal0gKyANCiAgICAgIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IkRhcmsyIikgKyAgDQogICAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iRGFyazIiKQ0KICAgICAgICB9DQp9DQpnIA0KYGBgDQoNCiogTGFzIHZhcmlhYmxlcyBzdXBlcmZpY2llIGN1YmllcnRhIHkgdG90YWwgcHJlc2VudGFuIHVuYSBhc29jaWFjacOzbiBsaW5lYWwgcG9zaXRpdmEgZnVlcnRlICgwLjk0NSkuDQoNClJlc3BlY3RvIGRlIG51ZXN0cmEgdmFyaWFibGUgYSBwcmVkZWNpciwgZWwgcHJlY2lvLCBvYnNlcnZhbW9zIHF1ZToNCg0KKiBFeGlzdGUgdW5hIGNvcnJlbGFjacOzbiBwb3NpdGl2YSBmdWVydGUgY29uIGxhcyBzdXBlcmZpY2llcyB0b3RhbCB5IGN1YmllcnRhLiBSZXNwZWN0byBhIGVzdGFzIMO6bHRpbWFzIGV4aXN0ZSB1bmEgZ3JhbiBkaWZlcmVuY2lhIGVuIGxhIGNvcnJlbGFjacOzbiBzZWfDum4gZWwgdGlwbyBkZSBwcm9waWVkYWQuIExhcyBjYXNhcyBwYXJlY2VuIHByZXNlbnRhciBtZW5vciBjb3JyZWxhY2nDs24gcXVlIGxvcyBkZXBhcnRhbWVudG9zIHkgUEhzLg0KDQoqIEV4aXN0ZSB1bmEgY29ycmVsYWNpw7NuIHBvc2l0aXZhIG1lbm9yIGNvbiBlbCBuw7ptZXJvIGRlIGhhYml0YWNpb25lcyB5IGJhw7Fvcy4gDQoNCiMjIFBhcnRpY2nDs24gZGVsIGRhdGFzZXQgZW4gdHJhaW4geSB0ZXN0DQoNCkVuIGVzdGUgY2FzbyBwYXJhIGV2YWx1YXIgbG9zIG1vZGVsb3MgdmFtb3MgYSByZWFsaXphciB1bmEgcGFydGljacOzbiBlbnRyZSBkYXRhc2V0IGRlIGVudHJlbmFtaWVudG8gKDc1JSkgeSB0ZXN0ZW8gKDI1JSkgdXNhbmRvIGxhIGZ1bmNpw7NuIGBpbml0aWFsX3NwbGl0YCBkZWwgcGFxdWV0ZSBbcnNhbXBsZV0oaHR0cHM6Ly9yc2FtcGxlLnRpZHltb2RlbHMub3JnLykgZGUgdGlkeW1vZGVscy4NCg0KYGBge3J9DQojIGZpamFtb3Mgc2VtaWxsYQ0Kc2V0LnNlZWQoMjAyMSkNCiMgUGFydGljacOzbiBUcmFpbiB5IFRlc3QsIGluZGljYW5kbyBwcm9wb3JjacOzbg0KdHJhaW5fdGVzdCA8LSBpbml0aWFsX3NwbGl0KGRhdG9zX3Byb3BlcmF0aSwgcHJvcCA9IDAuNzUpDQp0cmFpbl9kYXRhIDwtIHRyYWluaW5nKHRyYWluX3Rlc3QpDQp0ZXN0X2RhdGEgPC0gdGVzdGluZyh0cmFpbl90ZXN0KQ0KIyB2ZW1vcyBsYXMgZGltZW5zaW9uZXMgZGUgY2FkYSBwYXJ0aWNpb24NCnRyYWluX2RhdGEgJT4lDQogIGRpbV9kZXNjKCkgDQp0ZXN0X2RhdGEgJT4lDQogIGRpbV9kZXNjKCkgDQpgYGANCkVsIGRhdGFzZXQgZGUgdGVzdCBsbyB1dGlsaXphcmVtb3MgZW4gbGEgc2lndWllbnRlIGNsYXNlLiANCg0KIyMgTW9kZWxvIE3Dumx0aXBsZQ0KDQpFbCBtb2RlbG8gZGUgKipyZWdyZXNpw7NuIGxpbmVhbCBtw7psdGlwbGUqKiBlcyB1biBtb2RlbG8gcGFyYSBsYSB2YXJpYWJsZSBhbGVhdG9yaWEgWSBjdWFuZG8gc2UgY29ub2NlbiBsYXMgdmFyaWFibGVzIHJlZ3Jlc29yYXMuIEVzIG3Dumx0aXBsZSB5YSBxdWUgdmluY3VsYSB1bmEgc2VyaWUgZGUgdmFyaWFibGVzIHByZWRpY3RvcmFzIGNvbiBZLiANCg0KRWwgbW9kZWxvIGVuIHTDqXJtaW5vcyBkZSBsYXMgdmFyaWFibGVzOg0KDQokJFlfaSA9IM6yXzAgKyDOsl8xWF97aTF9ICsgzrJfMlhfe2kyfSArIMK3IMK3IMK3ICsgzrJfe3AtMX1YX3tpcC0xfSArIM61X2kkJA0KZG9uZGUgJM6yXzAkLCAkzrJfMSQsLi4sICTOsl97cOKIkjF9JCBzb24gcGFyw6FtZXRyb3MgZGVzY29ub2NpZG9zLCAkWF97aTF9JCwgJFhfe2kyfSQsIC4uLiwgJFhfe2lwLTF9JCBzb24gbG9zIHZhbG9yZXMgZGUgbGFzIHZhcmlhYmxlcyBwcmVkaWN0b3JhcyBtZWRpZGFzIGVuIGVsIGktw6lzaW1vIGluZGl2aWR1bywgJFlfaSQgZXMgbGEgdmFyaWFibGUgcmVzcHVlc3RhIG1lZGlkYSBlbiBlbCBpLcOpc2ltbyBpbmRpdmlkdW8gKG9ic2VydmFkbykgeSAkzrVfaSQgZXMgZWwgZXJyb3IgcGFyYSBlbCBpbmRpdmlkdW8gaS3DqXNpbW8gKG5vIG9ic2VydmFibGUpLg0KDQoqKlN1cHVlc3RvcyBkZWwgbW9kZWxvIGxpbmVhbCoqDQoNClNlIHB1ZWRlbiByZXN1bWlyIGNvbW8gJM+1X2kkIH4gJE4oMCzPg14yKSQgcGFyYSB0b2RvICQxPGk8biQsIGluZGVwZW5kaWVudGVzIGVudHJlIHPDrS4NCg0KRWwgbW9kZWxvIGVuIHTDqXJtaW5vcyBkZSBsYSBlc3BlcmFuemEgY29uZGljaW9uYWwgZGUgWSBkYWRhcyAkWF8xJCwgJFhfMiQsLi4uLCAkWF97cC0xfSQ6DQoNCiQkRShZfFhfMSxYXzIsLi4uWF97cC0xfSkgPSDOsl8wICsgzrJfMVhfe2kxfSArIM6yXzJYX3tpMn0gKyDCtyDCtyDCtyArIM6yX3twLTF9WF97aXAtMX0kJA0KDQpFbCBtb2RlbG8gc2UgZGVub21pbmEgKmxpbmVhbCogcHVlc3RvIHF1ZSBsYSBlc3BlcmFuemEgZGUgWSBjb25kaWNpb25hbCBhIGxhcyBYJ3MgZGVwZW5kZSBsaW5lYWxtZW50ZSBkZSBsYXMgY292YXJpYWJsZXMgJFhfMSQsICRYXzIkLC4uLiwgJFhfe3AtMX0kLiANCg0KIyMjIEVzdGltYWNpw7NuIGRlIGxvcyBQYXLDoW1ldHJvcyAoYWp1c3RlIGRlbCBtb2RlbG8pDQoNClNlIHF1aWVyZSBhanVzdGFyIHVuIG1vZGVsbyBwYXJhIGVsIHByZWNpbyBkZSBsYXMgcHJvcGllZGFkZXMgZW4gZnVuY2nDs24gZGUgMiB2YXJpYWJsZXM6DQoNCiRwcmVjaW8gPSBcYmV0YV8wICsgXGJldGFfMXhfe2kxfSArIFxiZXRhXzJ4X3tpMn0gKyBcZXBzaWxvbl9pJA0KDQpWZWFtb3MgY8OzbW8gc2UgaW50ZXJwcmV0YW4gbG9zIGFqdXN0ZXMgcGFyYSBsb3MgZGlzdGludG9zIHRpcG9zIGRlIHByZWRpY3RvcmVzLiANCg0KIyMjICoxKSBQcmVkaWN0b3JlcyBudW3DqXJpY29zKg0KDQpBcm1lbW9zIHVuIG1vZGVsbyBwYXJhIHByZWRlY2lyIGVsIHByZWNpbyBlbiBmdW5jacOzbiBkZSBsYSBzdXBlcmZpY2llIGN1YmllcnRhIHkgbGEgY2FudGlkYWQgZGUgaGFiaXRhY2lvbmVzLiBWZWFtb3MgbG9zIHJlc3VsdGFkb3MgZGVsIG1vZGVsbyBlbXBsZWFuZG8gbGEgZnVuY2nDs24gdGlkeSgpLiANCg0KYGBge3J9DQojIGFqdXN0YW1vcyBtb2RlbG8gbGluZWFsIG11bHRpcGxlDQptb2RlbG9fc2NfciA8LSBsbShwcmljZSB+IHN1cmZhY2VfY292ZXJlZCArIHJvb21zLCBkYXRhID0gdHJhaW5fZGF0YSkNCiMgUmVzdW1lbiBkZWwgbW9kZWxvDQp0aWR5X3NjX3IgPC0gdGlkeShtb2RlbG9fc2NfciwgY29uZi5pbnQgPSBUUlVFKQ0KdGlkeV9zY19yDQpgYGANCg0KIyMjIyBTaWduaWZpY2FkbyBkZSBsb3MgY29lZmljaWVudGVzIGVzdGltYWRvcw0KDQoqIEVsIHZhbG9yIGRlICRcaGF0e1xiZXRhXzB9JCAob3JkZW5hZGEgYWwgb3JpZ2VuKSBlcyBgciByb3VuZCh0aWR5X3NjX3IkZXN0aW1hdGVbMV0pYCBkw7NsYXJlcywgbG8gcXVlIGNvcnJlc3BvbmRlIGFsIHByZWNpbyAqKmVzcGVyYWRvKiogZGUgdW5hIHByb3BpZWRhZCBjb24gMCBoYWJpdGFjaW9uZXMgeSBzaW4gc3VwZXJmaWNpZS4gTG8gY3VhbCwgZXN0ZSBjYXNvIGNhcmVjZXLDrWEgZGUgc2VudGlkbyB5YSBxdWUgbGFzIHByb3BpZWRhZGVzIGRlYmVyw61hbiB0ZW5lciBzdXBlcmZpY2llIHkgYWwgbWVub3MgYWxndW5hIGhhYml0YWNpw7NuL2FtYmllbnRlLiAgDQoNCiogRWwgY29lZmljaWVudGUgZXN0aW1hZG8gZGUgJFxoYXR7XGJldGFfe3N1cmZhY2VcX2NvdmVyZWR9fSQgKHN1cGVyZmljaWUgY3ViaWVydGEpIGVzIGRlIGByIHJvdW5kKHRpZHlfc2NfciRlc3RpbWF0ZVsyXSlgIGTDs2xhcmVzLCBsbyBxdWUgaW5kaWNhIHF1ZSBzaSBtYW50ZW5lbW9zIGVsIG7Dum1lcm8gZGUgaGFiaXRhY2lvbmVzIGNvbnN0YW50ZSwgY2FkYSBpbmNyZW1lbnRvIGRlIHVuIG0yIGFkaWNpb25hbCBkZSBzdXBlcmZpY2llIGNvcnJlc3BvbmRlIGEgdW4gYXVtZW50byBkZSBgciByb3VuZCh0aWR5X3NjX3IkZXN0aW1hdGVbMl0pYCBkw7NsYXJlcywgKiplbiBwcm9tZWRpbyoqIGVuIGVsIHByZWNpbyBkZSBsYSBwcm9waWVkYWQuIE8gbG8gcXVlIGVzIGlndWFsLCBkYWRhcyBkb3MgcHJvcGllZGFkZXMgY29uIGxhIG1pc21hIGNhbnRpZGFkIGRlIGhhYml0YWNpb25lcyBwZXJvIHRlbmllbmRvIHVuYSB1biBtMiBtw6FzIGRlIHN1cGVyZmljaWUgcXVlIGxhIG90cmEsIGVsIHByZWNpbyAqKmVzcGVyYWRvKiogcGFyYSBsYSBkZSBtYXlvciBzdXBlcmZpY2llIHNlcsOhIGByIHJvdW5kKHRpZHlfc2NfciRlc3RpbWF0ZVsyXSlgIGTDs2xhcmVzIG3DoXMgYWx0byBxdWUgbGEgZGUgbWVub3Igc3VwZXJmaWNpZS4NCg0Kwr9Dw7NtbyBzZSBpbnRlcnByZXRhcsOtYSBlbCBjb2VmaWNpZW50ZSBlc3RpbWFkbyBkZWwgbsO6bWVybyBkZSBoYWJpdGFjaW9uZXM/DQoNCiMjIyAqMikgUHJlZGljdG9yZXMgQ2F0ZWfDs3JpY29zKg0KDQpBcm1lbW9zIHVuIG1vZGVsbyBwYXJhIHByZWRlY2lyIGVsIHByZWNpbyBkZSBsYSBwcm9waWVkYWQgZW4gZnVuY2nDs24gZGUgbGEgc3VwZXJmaWNpZSBjdWJpZXJ0YSB5IGVsIHRpcG8gZGUgcHJvcGllZGFkICgqcHJvcGVydHlfdHlwZSopLCBxdWUgZXMgY2F0ZWfDs3JpY2EgY29uIHRyZXMgbml2ZWxlcyAoQ2FzYSwgRGVwYXJ0YW1lbnRvIG8gUEgpLiBQYXJhIGVsbG8sIHZhbW9zIGEgYW5hbGl6YXIgcHJpbWVybyBlbCBjb21wb3J0YW1pZW50byBkZSBsYSB2YXJpYWJsZSBxdWUgcXVlcmVtb3MgcHJlZGVjaXIgcGFyYSBjYWRhIHRpcG8gZGUgcHJvcGllZGFkIGEgdHJhdsOpcyBkZSB1biBib3hwbG90LiANCg0KYGBge3J9DQojIGFybWFtb3MgYm94cGxvdHMgcGFyYWxlbG9zIGRlIHByZWNpbyBzZWd1biBlbCB0aXBvIGRlIHByb3BpZWRhZCAoY2FzYSwgZHB0byBvIHBoKQ0KZ2dwbG90KGRhdGEgPSB0cmFpbl9kYXRhLCBhZXMoeSA9IHByZWNpb19lbl9taWxlcywgZ3JvdXAgPSBwcm9wZXJ0eV90eXBlLCBmaWxsID0gcHJvcGVydHlfdHlwZSkpICsNCiAgICAgICAgIGdlb21fYm94cGxvdCgpICsgDQogICAgICAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJEYXJrMiIpICsNCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkgKw0KICAgICAgICAgbGFicyh0aXRsZSA9ICJCb3hwbG90cyBkZSBwcmVjaW8gc2Vnw7puIHRpcG8gZGUgcHJvcGllZGFkIiwgc3VidGl0bGUgPSAiRW4gbWlsZXMgZGUgZMOzbGFyZXMiKSArDQogIGxhYnMoeSA9ICJQcmVjaW8gZW4gbWlsZXMgZGUgVVNEIikgKw0KICBsYWJzKHggPSAiVGlwbyBkZSBwcm9waWVkYWQiKSArDQogIGZhY2V0X3dyYXAofnByb3BlcnR5X3R5cGUpDQpgYGANCmBgYHtyfQ0KIyBBY290YW5kbyBsYSBlc2NhbGEgZGVsIGdyYWZpY28gcGFyYSB2aXN1YWxpemFyIG1lam9yIGVsIHJhbmdvIGludGVyY3VhcnRpbA0KZ2dwbG90KGRhdGEgPSB0cmFpbl9kYXRhLCBhZXMoeSA9IHByZWNpb19lbl9taWxlcywgZ3JvdXAgPSBwcm9wZXJ0eV90eXBlLCBmaWxsID0gcHJvcGVydHlfdHlwZSkpICsNCiAgICAgICAgIGdlb21fYm94cGxvdCgpICsgDQogICAgICAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJEYXJrMiIpICsNCiAgdGhlbWVfYncoKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEwMDApKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkgKw0KICAgICAgICAgbGFicyh0aXRsZSA9ICJCb3hwbG90cyBkZSBwcmVjaW8gc2Vnw7puIHRpcG8gZGUgcHJvcGllZGFkIiwgc3VidGl0bGUgPSAiRW4gbWlsZXMgZGUgZMOzbGFyZXMiKSArDQogIGxhYnMoeSA9ICJQcmVjaW8gZW4gbWlsZXMgZGUgVVNEIikgKw0KICBsYWJzKHggPSAiVGlwbyBkZSBwcm9waWVkYWQiKSArDQogIGZhY2V0X3dyYXAofnByb3BlcnR5X3R5cGUpDQpgYGANCkFuYWxpemFuZG8gbGEgdmFyaWFibGUgZGUgKnRpcG8gZGUgcHJvcGllZGFkKiBlbiBmdW5jacOzbiBkZSBsYSB2YXJpYWJsZSBhIHByZWRlY2lyLCBzZSBvYnNlcnZhIHVuYSBkaWZlcmVuY2lhIGVuIGxvcyBwcmVjaW9zIHNlZ8O6biBlbCB0aXBvIGRlIHByb3BpZWRhZC4gRW4gcGFydGljdWxhciwgbGFzIGNhc2FzIHByZXNlbnRhbiBtYXlvcmVzIHByZWNpb3MgeSBhIHN1IHZleiwgbWF5b3IgdmFyaWFiaWxpZGFkIHF1ZSBsb3MgZGVwYXJ0YW1lbnRvcyB5IFBIcy4gDQoNClZlYW1vcyBxdcOpIG9jdXJyZSBjdWFuZG8gKiphanVzdGFtb3MgZWwgbW9kZWxvKio6DQoNCmBgYHtyfQ0KIyBhanVzdGFtb3MgZWwgbW9kZWxvIGRlIHN1cGVyZmljaWUgeSB0aXBvIGRlIHByb3BpZWRhZA0KbW9kZWxvX3NjX3B0IDwtIGxtKHByaWNlIH4gc3VyZmFjZV9jb3ZlcmVkICsgcHJvcGVydHlfdHlwZSwgZGF0YSA9IHRyYWluX2RhdGEpDQp0aWR5X3NjX3B0IDwtIHRpZHkobW9kZWxvX3NjX3B0LCBjb25mLmludCA9IFRSVUUpDQp0aWR5X3NjX3B0DQpgYGANCg0KIyMjIyBTaWduaWZpY2FkbyBkZSBsb3MgY29lZmljaWVudGVzIGVzdGltYWRvcw0KDQrCv0PDs21vIGNhbWJpYSBsYSAqKmludGVycHJldGFjacOzbioqIGRlIGxvcyBjb2VmaWNpZW50ZXMgcGFyYSBsYSB2YXJpYWJsZSBjYXRlZ8OzcmljYT8NCg0KRWwgbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsIGVuIGVzdGUgY2FzbyBjb25zaXN0ZSBzaW1wbGVtZW50ZSBlbiBleHByZXNhcg0KbGEgbWVkaWEgZGVsIG5pdmVsIGRlIHByZWNpb3MgZW4gY2FkYSBwb2JsYWNpw7NuIChkZSBjYXNhcywgZGVwYXJ0YW1lbnRvcyBvIFBIcykgbWVkaWFudGUgdHJlcyBjb2VmaWNpZW50ZXMgZGlzdGludG9zLCBkb25kZTogDQoNCiogJFxiZXRhXzAkIChjYXRlZ29yw61hIGJhc2FsIGRlIHZhcmlhYmxlIGNhdGVnw7NyaWNhKSBlcyBsYSBtZWRpYSBkZWwgcHJlY2lvIHBhcmEgbGFzIENhc2FzIHNpbiBzdXBlcmZpY2llLiBFbiBlc3RlIG1vZGVsbyBlcyBkZSBgciByb3VuZCh0aWR5X3NjX3B0JGVzdGltYXRlWzFdKWAgZMOzbGFyZXMsIGxvIHF1ZSBjYXJlY2UgZGUgc2VudGlkbyBlY29uw7NtaWNvIHlhIHF1ZSBsYXMgY2FzYXMgZGViZXLDrWFuIHRlbmVyIGFsZ3VuYSBzdXBlcmZpY2llIHkgbm8gcG9kcsOtYW4gdGVuZXIgdW4gcHJlY2lvIG5lZ2F0aXZvLiAgDQoNCiogJFxiZXRhXzAgKyBcYmV0YV97cHJvcGVydHlcX3R5cGVEZXBhcnRhbWVudG99JCBlcyBsYSBtZWRpYSBkZWwgcHJlY2lvIHBhcmEgbG9zIGRlcGFydGFtZW50b3MsIGRhZGEgbGEgc3VwZXJmaWNpZS4gUG9yIGxvIHRhbnRvLCAkXGJldGFfe3Byb3BlcnR5XF90eXBlRGVwYXJ0YW1lbnRvfSQgZXMgbGEgZGlmZXJlbmNpYSBlbiBsb3MgKipuaXZlbGVzIG1lZGlvcyoqIGRlIHByZWNpb3MgZGUgbG9zIGRlcGFydGFtZW50b3MgcmVzcGVjdG8gZGUgbGFzIGNhc2FzIChjYXRlZ29yw61hIGJhc2FsKS5FcyBkZWNpciwgJFxiZXRhX3twcm9wZXJ0eVxfdHlwZURlcGFydGFtZW50b30kIChgciByb3VuZCh0aWR5X3NjX3B0JGVzdGltYXRlWzNdKWApIGluZGljYSBjdcOhbnRvIG3DoXMgYWx0YSBlcyBsYSBmdW5jacOzbiBkZSByZXNwdWVzdGEgKHByZWNpbykgcGFyYSBsb3MgZGVwYXJ0YW1lbnRvcyByZXNwZWN0byBkZSBsYXMgY2FzYXMgKGNhdGVnb3LDrWEgYmFzYWwpLCBkYWRhIGxhIHN1cGVyZmljaWUuDQoNCiogVmVtb3MgcXVlIGVsIG5pdmVsIG1lZGlvIGRlbCBwcmVjaW8gZXMgdW5hIGZ1bmNpw7NuIGxpbmVhbCBkZSBsYSBzdXBlcmZpY2llIGRlIGxhIHByb3BpZWRhZCwgY29uIHVuYSBtaXNtYSBwZW5kaWVudGUgJFxiZXRhX3tzdXJmYWNlX3RvdGFsfSQgYHIgcm91bmQodGlkeV9zY19wdCRlc3RpbWF0ZVsyXSlgIHBhcmEgY2FzYXMsIGRlcGFydGFtZW50b3MgeSBQSHMuIA0KDQrCv0PDs21vIHNlIGludGVycHJldGFyw61hIGVudG9uY2VzICRcYmV0YV97cHJvcGVydHlcX3R5cGVQSH0kPyDCv1kgJFxiZXRhXzAgKyBcYmV0YV97cHJvcGVydHlcX3R5cGVQSH0kPw0KDQojIyMjIEdyYWZpcXVlbW9zIGxhIHJlZ3Jlc2nDs24gcGFyYSBsYXMgdHJlcyBwb2JsYWNpb25lcw0KDQpBIGNvbnRpbnVhY2nDs24gc2UgbXVlc3RyYSBlbCBncsOhZmljbyBkZSBlc3RhIHNpdHVhY2nDs24gZW4gcXVlIHRlbmVtb3MgdW5hIHZhcmlhYmxlIGNhdGVnw7NyaWNhIGNvbiB0cmVzIG5pdmVsZXMgeSB1bmEgbnVtw6lyaWNhLiBEZSBsYSBpbnRlcnByZXRhY2nDs24gZGUgY29lZmljaWVudGVzLCBzZSBwdWRvIHZlciBxdWUgbGEgcmVncmVzacOzbiBzZSBwdWVkZSBleHByZXNhciBjb21vIHJlY3RhcyBwYXJhbGVsYXMgY29uIGlndWFsIHBlbmRpZW50ZSBwZXJvIGRpc3RpbnRvIGludGVyY2VwdG8uIFZlYW1vcyBjw7NtbyBoYWNlcmxhLiANCg0KYGBge3J9DQojIEFjY2VkZW1vcyBhIGxhIGluZm9ybWFjacOzbiBkZSBsb3MgY29lZmljaWVudGVzIGVzdGltYWRvcw0KaW50ZXJjZXB0b19DID0gbW9kZWxvX3NjX3B0JGNvZWZmaWNpZW50c1sxXSAjIM6yMA0KcGVuZGllbnRlID0gbW9kZWxvX3NjX3B0JGNvZWZmaWNpZW50c1syXSAjIM6yMQ0KaW50ZXJjZXB0b19EID0gbW9kZWxvX3NjX3B0JGNvZWZmaWNpZW50c1sxXSArIG1vZGVsb19zY19wdCRjb2VmZmljaWVudHNbM10gIyDOsjAgKyDOsjINCmludGVyY2VwdG9fUEggPSBtb2RlbG9fc2NfcHQkY29lZmZpY2llbnRzWzFdICsgbW9kZWxvX3NjX3B0JGNvZWZmaWNpZW50c1s0XSAjIM6yMCArIM6yMw0KIyBHcmFmaWNhbW9zIGVsIGRhdGFzZXQgeSBlbCBtb2RlbG8NCnRyYWluX2RhdGEgJT4lIGdncGxvdCguLCBhZXMoeCA9IHN1cmZhY2VfY292ZXJlZCwgeSA9IHByaWNlKSkgKyANCiAgZ2VvbV9wb2ludCgpICsgI2NhcGEgZGUgbG9zIGRhdG9zDQogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGludGVyY2VwdG9fQywgc2xvcGUgPSBwZW5kaWVudGUsIGNvbG9yID0gImZvcmVzdGdyZWVuIiwgc2l6ZT0xKSArICMgY2FwYSBkZWwgbW9kZWxvDQogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGludGVyY2VwdG9fRCwgc2xvcGUgPSBwZW5kaWVudGUsIGNvbG9yID0gImRhcmtvcmFuZ2UiLCBzaXplPTEpICsgIyBjYXBhIGRlbCBtb2RlbG8gDQogICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gaW50ZXJjZXB0b19QSCwgc2xvcGUgPSBwZW5kaWVudGUsIGNvbG9yID0gInNsYXRlYmx1ZTMiLCBzaXplPTEpICsgIyBjYXBhIGRlbCBtb2RlbG8gDQogIHRoZW1lX2J3KCkgKw0KICBsYWJzKHRpdGxlPSJNb2RlbG8gTGluZWFsIE3Dumx0aXBsZTogU3VwZXJmaWNpZSB5IFRpcG8gZGUgUHJvcGllZGFkIiwgeD0iU3VwZXJmaWNpZSBlbiBtMiIsIHk9IlByZWNpbyBlbiBtaWxlcyBkZSBVU0QiKSANCmBgYA0KDQojIyMgKlByZWRpY3RvcmVzIEN1YWxpdGF0aXZvcyBjb24gbXVjaGFzIGNsYXNlcyoNCg0KTGEgdmFyaWFibGUgYmFycmlvcyAobDMpIHRpZW5lIDU3IG5pdmVsZXMgZGlzdGludG9zLiBWZWFtb3MgYSB0cmF2w6lzIGRlIGJveHBsb3RzIHBhcmFsZWxvcyBjw7NtbyBzZSBjb21wb3J0YW4uIA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTV9DQpsZW5ndGgodW5pcXVlKGRhdG9zX3Byb3BlcmF0aSRsMykpICMgNTcgYmFycmlvcw0KIyBhcm1vIHNjYXR0ZXJwbG90IGRlIHByZWNpb3MgZW4gbWlsZXMgZW4gZnVuY2nDs24gZGUgc3VwZXJmaWNpZSB0b3RhbA0KZ2dwbG90KCBkYXRvc19wcm9wZXJhdGksIGFlcyh4ID0gZmN0X3Jlb3JkZXIobDMsIHByaWNlLCAuZGVzYyA9IFQpLCB5ID0gcHJpY2UvMTAwMCkpICsgDQogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNzUsIGFlcyhmaWxsID0gbDMpKSArIA0KICB0aGVtZV9taW5pbWFsKCkgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKSsNCiAgbGFicyh5ID0gIlByZWNpb3MgZW4gbWlsZXMiLCB4ID0gIkJhcnJpb3MiKSAgKw0KICBnZ3RpdGxlKCJCb3hwbG90cyBkZSBwcmVjaW9zIGVuIGZ1bmNpw7NuIGRlIGxvcyBiYXJyaW9zIikrDQogIHRoZW1lIChheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYWNlPSJpdGFsaWMiLCBjb2xvdXI9ImRhcmsgZ3JleSIsIHNpemUgPSA4LCBhbmdsZSA9IDkwKSkNCmBgYA0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQ0KIyBhcm1hbW9zIHNjYXR0ZXJwbG90IGRlIHByZWNpb3MgZW4gbWlsZXMgZW4gZnVuY2nDs24gZGUgc3VwZXJmaWNpZSB0b3RhbA0KZ2dwbG90KGRhdG9zX3Byb3BlcmF0aSwgYWVzKHggPSBmY3RfcmVvcmRlcihsMywgcHJpY2UsIC5kZXNjID0gVCksIHkgPSBwcmljZS8xMDAwKSkgKyANCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSwgYWxwaGEgPSAwLjc1LCBhZXMoZmlsbCA9IGwzKSkgKyANCiAgdGhlbWVfbWluaW1hbCgpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrDQogIGxhYnMoeSA9ICJQcmVjaW9zIGVuIG1pbGVzIiwgeCA9ICJCYXJyaW9zIikgICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMTIwMCkpICsNCiAgZ2d0aXRsZSgiQm94cGxvdHMgZGUgcHJlY2lvcyBlbiBmdW5jacOzbiBkZSBsb3MgYmFycmlvcyIpKw0KICB0aGVtZSAoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZT0iaXRhbGljIiwgY29sb3VyPSJkYXJrIGdyZXkiLCBzaXplID0gOCwgYW5nbGUgPSA5MCkpDQpgYGANCg0KRW4gbG9zIGJveHBsb3RzIHBhcmFsZWxvcyBkZSBwcmVjaW9zIHBvciBiYXJyaW9zIHNlIHB1ZWRlIHZlciBxdWUgZW50cmUgbG9zIGJhcnJpb3MgcXVlIHByZXNlbnRhbiBtYXlvcmVzIHByZWNpb3Mgc2UgdWJpY2FuOiBQdWVydG8gTWFkZXJvLExhcyBDYcOxaXRhcywgQ2F0YWxpbmFzLCBSZWNvbGV0YSB5IEJlbGdyYW5vLCBtaWVudHJhcyBxdWUgVmlsbGEgU29sZGF0aSwgQ29uc3RpdHVjacOzbiwgVmlsbGEgbHVnYW5vIHkgbGEgQm9jYSBwcmVzZW50YW4gbG9zIG1lbm9yZXMgcHJlY2lvcyBkZSBwcm9waWVkYWRlcy4gDQoNClByb2JlbW9zICoqYWp1c3RhciB1biBtb2RlbG8gbGluZWFsKiogcGFyYSBlbCBwcmVjaW8gZW4gZnVuY2nDs24gZGUgbGEgc3VwZXJmaWNpZSB0b3RhbCB5IGxvcyBiYXJyaW9zLiAgDQoNCmBgYHtyfQ0KIyBhanVzdGFtb3MgZWwgbW9kZWxvDQptb2RlbG9fc2NfbDMgPC0gbG0ocHJpY2UgfiBzdXJmYWNlX2NvdmVyZWQgKyBsMywgZGF0YSA9IHRyYWluX2RhdGEpDQp0aWR5X3NjX2wzIDwtIHRpZHkobW9kZWxvX3NjX2wzLCBjb25mLmludCA9IFRSVUUpDQp0aWR5X3NjX2wzDQpgYGANCg0KUiBjdWFuZG8gZWZlY3TDumEgbGEgcmVncmVzacOzbiBjYWxjdWxhIGF1dG9tw6F0aWNhbWVudGUgbGFzIHZhcmlhYmxlcyBpbmRpY2Fkb3JhcyAoZHVtbWllcykgcGFyYSBsYXMgY292YXJpYWJsZXMgY2F0ZWfDs3JpY2FzLCBlbiBnZW5lcmFsIHNlZ8O6biBvcmRlbiBhbGZhYsOpdGljby4gUG9kZW1vcyBjaGVxdWVhciBlbCBvcmRlbiBwYXJhIHZlcmlmaWNhciBjdcOhbCBlcyBsYSBjYXRlZ29yw61hIGJhc2FsLiBFbiBlc3RlIGNhc28sIGxhIGNhdGVnb3LDrWEgZGUgcmVmZXJlbmNpYSBjb3JyZXNwb25kZSBhbCBiYXJyaW8gZGUgKkFiYXN0byouDQoNCiMjIyMgU2lnbmlmaWNhZG8gZGUgbG9zIGNvZWZpY2llbnRlcyBlc3RpbWFkb3MNCg0Kwr9RdcOpIHNpZ25pZmljYW4gbG9zIGNvZWZpY2llbnRlcyBkZSBlc3RhIHZhcmlhYmxlIGNhdGVnw7NyaWNhPw0KDQoqIEVzdGUgbW9kZWxvIHByb3BvbmUgYWp1c3RhciB1bmEgcmVjdGEgZGlzdGludGEgcGFyYSBlbCBwcmVjaW8gKiptZWRpbyoqDQpkZSBjYWRhIHBvYmxhY2nDs24gZGVmaW5pZGEgcG9yIGVsIGJhcnJpbywgdG9kYXMgY29uIGlndWFsIHBlbmRpZW50ZSAoZGVmaW5pZGEgcG9yIGxhIHN1cGVyZmljaWUpLCB5IDU3IG9yZGVuYWRhcyBhbCBvcmlnZW4gZGlmZXJlbnRlcywgdW5hIHBvciBjYWRhIGJhcnJpby4NCg0KKiBQb3IgZWplbXBsbywgZWxpZ2llbmRvIHVuIGJhcnJpbyBkZSBwcmVjaW9zIGFsdG9zLCB2ZW1vcyBxdWUgJFxiZXRhX3tCZWxncmFub30kIGluZGljYSBjdcOhbnRvIHNlIGluY3JlbWVudGEgZWwgcHJlY2lvIG1lZGlvIGRlIGxhcyBwcm9waWVkYWRlcyBwYXJhIGFxdWVsbG9zIGlubXVlYmxlcyB1YmljYWRvcyBlbiBCZWxncmFubyByZXNwZWN0byBkZSBhcXVlbGxvcyB1YmljYWRvcyBlbiBBYmFzdG8gKGNhdGVnb3LDrWEgYmFzYWwpLCBkYWRhIGxhIHN1cGVyZmljaWUuDQoNCiogQW5hbGl6YW5kbyB1biBiYXJyaW8gZGUgcHJlY2lvcyBiYWpvcywgJFxiZXRhX3tCb2NhfSQgaW5kaWNhIGN1w6FudG8gc2UgcmVkdWNlIGVsIHByZWNpbyBtZWRpbyBkZSBsYXMgcHJvcGllZGFkZXMgdWJpY2FkYXMgZW4gbGEgQm9jYSByZXNwZWN0byBkZSBhcXVlbGxhcyB1YmljYWRhcyBlbiBBYmFzdG8gKGNhdGVnb3LDrWEgYmFzYWwpLCBkYWRhIGxhIHN1cGVyZmljaWUuDQoNCiMjIEluZmVyZW5jaWEgZGUgbG9zICTOsl9rJCAodGVzdCBkZSBzaWduaWZpY2F0aXZpZGFkIGluZGl2aWR1YWwpDQoNCiMjIyMgVGVzdCBwYXJhIGxhcyAkzrJfayQNCg0KUGFyYSBldmFsdWFyIGxhIHNpZ25pZmljYXRpdmRhZCBpbmRpdmlkdWFsIGRlIGNhZGEgdW5hIGRlIGxhcyB2YXJpYWJsZXMgc2UgYW5hbGl6YSBlbCB0ZXN0IHQgcXVlIGJ1c2NhIHByb2JhciBzaSBlbCBjb2VmaWNpZW50ZSBkZSByZWdyZXNpw7NuIGNvcnJlc3BvbmRpZW50ZSBhIGRpY2hhIHZhcmlhYmxlIGVzIGRpc3RpbnRvIGRlIDAgKGZpZ3VyYSBlbiBsYSB0YWJsYSByZXN1bWVuIGRlIHJlc3VsdGFkb3MgZGUgbGEgcmVncmVzacOzbikuDQoNCkVzIGRlY2lyLCBidXNjYSBwcm9iYXI6ICANCg0KKiAkSF8wOiBcYmV0YV9rID0gMCQgDQoNCiogJEhfMTogXGJldGFfayDiiaAgMCQuIA0KDQoqKk1vZGVsbyBTdXBlcmZpY2llIHkgSGFiaXRhY2lvbmVzKioNCg0KYGBge3J9DQpvcHRpb25zKCJzY2lwZW4iPTEpDQp0aWR5X3NjX3IgJT4lDQogIHNlbGVjdCh0ZXJtLCBzdGF0aXN0aWMsIHAudmFsdWUsIGNvbmYubG93LCBjb25mLmhpZ2gpDQpgYGANCg0KKiBFbiBlc3RlIHByaW1lciBtb2RlbG8gc2Ugb2JzZXJ2YSBxdWUgdGFudG8gbGEgdmFyaWFibGUgKnN1cmZhY2VfdG90YWwqIGNvbW8gKnJvb21zKiByZXN1bHRhbiBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhcyBwYXJhIGV4cGxpY2FyIGVsIHByZWNpbyBkZSBsYXMgcHJvcGllZGFkZXMgKHAtdmFsb3JlcyA8IDAuMDUpLiANCg0KKiBBZGVtw6FzIGRlbCByZXN1bHRhZG8gZGVsIHRlc3QsIHBvZGVtb3MgYXByZWNpYXIgcXVlIGxvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSAoSUMpIGRlbCA5NSUgZGUgbGFzIHZhcmlhYmxlcyBkZSBzdXBlcmZpY2llIHkgaGFiaXRhY2lvbmVzIG5vIGNvbnRpZW5lbiBhbCAwLiANCg0KKipNb2RlbG8gU3VwZXJmaWNpZSB5IFRpcG8gZGUgUHJvcGllZGFkKioNCg0KYGBge3J9DQp0aWR5X3NjX3B0ICU+JQ0KICBzZWxlY3QodGVybSwgc3RhdGlzdGljLCBwLnZhbHVlLCBjb25mLmxvdywgY29uZi5oaWdoKSANCmBgYA0KDQoqIEVuIGVzdGUgY2FzbyB0YW1iacOpbiBzZSBvYnNlcnZhIHF1ZSB0b2RhcyBsYXMgdmFyaWFibGVzIHJlc3VsdGFuIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdmFzIHBhcmEgZXhwbGljYXIgYWwgcHJlY2lvIGRlIGxhcyBwcm9waWVkYWRlcyAocC12YWxvcmVzIDwgMC4wNSkuIA0KDQoqIEFkZW3DoXMgZGVsIHJlc3VsdGFkbyBkZWwgdGVzdCwgcG9kZW1vcyBjb3Jyb2JvcmFyIHF1ZSBsb3MgaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgZGVsIDk1JSBwYXJhIGxvcyBjb2VmaWNpZW50ZXMgZXN0aW1hZG9zIG5vIGNvbnRpZW5lbiBhbCAwIGVuIG5pbmd1bm8gZGUgbG9zIGNhc29zLiAgDQoNCiMjIyMjIMK/Q8OzbW8gc2UgaW50ZXJwcmV0YSBsYSBzaWduaWZpY2F0aXZpZGFkIGRlIGxhcyB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzPw0KDQoqIEVuIGVsIGNhc28gZGUgbGEgdmFyaWFibGUgdGlwbyBkZSBwcm9waWVkYWQsIGVzdGUgdGVzdCBwZXJtaXRlIGNoZXF1ZWFyIHNpIGxvcyB2YWxvcmVzIG1lZGlvcyBkZWwgcHJlY2lvIHNvbiBsb3MgbWlzbW9zIHBhcmEgbG9zIGRlcGFydGFtZW50b3MgbyBQSHMgcmVzcGVjdG8gZGUgbGFzIGNhc2FzIChjYXRlZ29yw61hIGJhc2FsKS4NCg0KKipNb2RlbG8gU3VwZXJmaWNpZSBUb3RhbCB5IEJhcnJpb3MqKiANCg0KYGBge3J9DQp0aWR5X3NjX2wzICU+JQ0KICBzZWxlY3QodGVybSwgc3RhdGlzdGljLCBwLnZhbHVlLCBjb25mLmxvdywgY29uZi5oaWdoKSAlPiUgDQogIGFycmFuZ2UocC52YWx1ZSkNCmBgYA0KDQoqIEVuIGVzdGUgbW9kZWxvIHNlIG9ic2VydmEgcXVlIG1pZW50cmFzIGxhIHZhcmlhYmxlIHN1cGVyZmljaWUgcmVzdWx0YSBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhIHBhcmEgZXhwbGljYXIgYWwgcHJlY2lvIChwLXZhbG9yZXMgPCAwLjA1KSwgbGFzIGNhdGVnb3LDrWFzIGRlIGJhcnJpb3Mgbm8uIEhheSBhbGd1bm9zIHF1ZSByZXN1bHRhbiBzaWduaWZpY2F0aXZvcyB5IG90cm9zIG5vLg0KDQoqIEVzdG8gbWlzbW8gc2Ugb2JzZXJ2YSBhIHRyYXbDqXMgZGUgbG9zIGludGVydmFsb3MgZGUgY29uZmlhbnphIGRlbCA5NSUgZG9uZGUgYWxndW5vcyBjb250aWVuZW4gYWwgMCAocG9yIGVqLiBDYWJhbGxpdG8pIHkgb3Ryb3Mgbm8gKHBvciBlai4gUHVlcnRvIE1hZGVybykuICANCg0KIyMjIyMgwr9Dw7NtbyBzZSBpbnRlcnByZXRhIGxhIHNpZ25pZmljYXRpdmlkYWQgZGUgbGFzIHZhcmlhYmxlcyBpbmRpY2Fkb3Jhcz8NCg0KKiBFc3RlIHRlc3QgcGVybWl0ZSBjaGVxdWVhciBzaSBsb3MgdmFsb3JlcyBtZWRpb3MgZGVsIHByZWNpbyBkZSBwcm9waWVkYWRlcyBzb24gbG9zIG1pc21vcyBlbiBsb3MgZGlzdGludG9zIGJhcnJpb3MgcmVzcGVjdG8gZGUgbGEgY2F0ZWdvcsOtYSBiYXNhbC4gQ2FiZSBkZXN0YWNhciwgcXVlIGVzdG9zIHAtdmFsb3JlcyBzb24gdsOhbGlkb3MgcGFyYSBsYXMgY29tcGFyYWNpb25lcyBpbmRpdmlkdWFsZXMgcmVzcGVjdG8gZGUgbGEgY2F0ZWdvcsOtYSBiYXNhbCBwZXJvIG5vIGFiYXJjYW4gdG9kYXMgbGFzIGNvbXBhcmFjaW9uZXMgZGUgYSBwYXJlcy4NCg0KKiBFcyBkZWNpciwgcXVlIGxvcyBuaXZlbGVzIG1lZGlvcyBkZSBwcmVjaW8gZGUgaW5tdWVibGVzIGVuIGxvcyBkaXN0aW50b3MgYmFycmlvcyBlbiBhbGd1bm9zIGNhc29zIGRpZmllcmVuIGRlIGxvcyBuaXZlbGVzIG1lZGlvcyBkZWwgQWJhc3RvIChiYXNhbCkgeSBlbiBvdHJvcyBuby4NCg0KKiBTaSBxdWVyZW1vcyBldmFsdWFyIGxhcyB2YXJpYWJsZXMgKnByb3BlcnR5X3R5cGUqIG8gKmwzKiBlbiBzdSBjb25qdW50bywgZGViZW1vcyByZWN1cnJpciBhIHVuIHRlc3QgRi4gDQoNCiMjIFRlc3QgRiAodGVzdCBkZSBzaWduaWZpY2F0aXZpZGFkIGdsb2JhbCkNCg0KRWwgdGVzdCBjb25qdW50byBGICh5IHN1IGNvcnJlc3BvbmRpZW50ZSBwLXZhbG9yKSBwZXJtaXRlIG1lZGlyIGxhIHNpZ25pZmljYXRpdmlkYWQgY29uanVudGEgZGUgdW5hIHZhcmlhYmxlIGNhdGVnw7NyaWNhIHBhcmEgZXhwbGljYXIgbGEgcmVzcHVlc3RhLg0KDQpUZXN0IEYgc2UgY29uc3RydXllIHBhcmEgdGVzdGVhciBzaSB2YXJpb3MgcGFyw6FtZXRyb3Mgc29uIGNlcm8sIGVzIGRlY2lyLCBwYXJhIHByb2JhciBsYXMgaGlww7N0ZXNpczoNCg0KKiAkSF8wOiDOsl8xID0gzrJfMiA9IMK3IMK3IMK3ID0gzrJfe3DiiJIxfSA9IDAkDQoNCiogJEhfMTokIG5vIHRvZG9zIGxvcyAkzrJfayQgKCRrID0gMSwgMiwuLi4sIHDiiJIxJCkgc29uIGlndWFsZXMgYSAwLiANCg0KRGljaG9zIHRlc3RzIEYgc2Ugb2J0aWVuZW4gcGFyYSBjYWRhIHZhcmlhYmxlIGRlIGxhIHRhYmxhIGRlIEFOT1ZBIGRlbCBtb2RlbG8uIFZlYW1vcyBxdcOpIG9jdXJyZSBlbiBlc3RlIGNhc28uIA0KDQpgYGB7cn0NCiMgTW9kZWxvIFN1cGVyZmljaWUgVG90YWwgeSBUaXBvIGRlIFByb3BpZWRhZA0KdGlkeShhbm92YShtb2RlbG9fc2NfcHQpKQ0KYGBgDQoNCkxhIHRhYmxhIGRlIEFOT1ZBIG11ZXN0cmEgcXVlLCBzZWfDum4gZWwgcmVzdWx0YWRvIGRlbCB0ZXN0IEYsIGxhIHZhcmlhYmxlICpwcm9wZXJ0eV90eXBlKiBlbiBzdSBjb25qdW50byByZXN1bHRhIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdmEgcGFyYSBleHBsaWNhciBhbCBwcmVjaW8gKHAtdmFsb3IgPCAwLjA1KS4NCg0KYGBge3J9DQojIE1vZGVsbyBTdXBlcmZpY2llIFRvdGFsIHkgQmFycmlvcw0KdGlkeShhbm92YShtb2RlbG9fc2NfbDMpKQ0KYGBgDQoNCkxhIHRhYmxhIGRlIEFOT1ZBIG11ZXN0cmEgcXVlLCBzZWfDum4gZWwgcmVzdWx0YWRvIGRlbCB0ZXN0IEYsIGxhIHZhcmlhYmxlICpsMyogZW4gc3UgY29uanVudG8gcmVzdWx0YSBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhIHBhcmEgZXhwbGljYXIgYWwgcHJlY2lvIChwLXZhbG9yIDwgMC4wNSkuIEVzIGRlY2lyLCBxdWUgcGVzZSBhIHF1ZSBhbGd1bmFzIGNhdGVnb3LDrWFzIGVuIHN1IGNvbXBhcmFjacOzbiBpbmRpdmlkdWFsIGNvbiBsYSBjYXRlZ29yw61hIGJhc2FsIHNlYW4gcG9jbyBzaWduaWZpY2F0aXZhcywgbGEgdmFyaWFibGUgZW4gc3UgY29uanVudG8gc8OtIHJlc3VsdGEgc2lnbmlmaWNhdGl2YSBwYXJhIGVsIG1vZGVsby4gDQoNClNpIGVzdGUgdGVzdCBubyByZXN1bHRhcmEgc2lnbmlmaWNhdGl2bywgc3VlbGUgZGVzY2FydGFyc2UgbGEgdmFyaWFibGUgY2F0ZWfDs3JpY2EgZGUgZW50cmUgbGFzIGNvdmFyaWFibGVzIGRlIGludGVyw6lzLCB5IHNlIGxhIGV4Y2x1eWUgZGVsIG1vZGVsby4gUG9yIGVsIGNvbnRyYXJpbywgc2kgZXN0ZSB0ZXN0IHJlc3VsdGEgZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2bywgZW50b25jZXMgc3VlbGVuIG1pcmFyc2UgY29uIG3DoXMgZGV0YWxsZSBjdcOhbGVzIGRlIGxhcyBjb21wYXJhY2lvbmVzIGVudHJlIGdydXBvcyBzb24gZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2YXMsIHBhcmEgcHJvcG9yY2lvbmFyIHVuIG1lam9yIGFuw6FsaXNpcyBkZSBsb3MgZGF0b3MuIA0KDQpPdHJhIGFsdGVybmF0aXZhIHNlcsOtYSBnZW5lcmFyIHVuYSBudWV2YSB2YXJpYWJsZSBjb24gbWVub3IgbsO6bWVybyBkZSB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzIHF1ZSBzZWFuIHNpZ25pZmljYXRpdmFzLCBzaW4gcGVyZGVyIGNhcGFjaWRhZCBleHBsaWNhdGl2YS4gUG9yIGVqZW1wbG8sIHNlIHBvZHLDrWEgYXJtYXIgdW5hIG51ZXZhIHZhcmlhYmxlIHF1ZSBhZ3J1cGUgbG9zIGJhcnJpb3MuIA0KDQojIyMgR2VuZXJhY2nDs24gZGUgbnVldmEgdmFyaWJsZSBgdGlwb19iYXJyaW9gDQoNCiogU2UgY3JlYSB1bmEgbnVldmEgdmFyaWFibGUgYHRpcG9fYmFycmlvYCBxdWUgY2xhc2lmaWNhIGEgbG9zIGJhcnJpb3Mgc2Vnw7puIGVsIHByZWNpbyBwb3IgbWV0cm8gY3VhZHJhZG8gcHJvbWVkaW8gZGUgbGFzIHByb3BpZWRhZGVzIGVuIGVsbG9zLCBkZSBhY3VlcmRvIGEgcHJlY2lvcyBhbHRvcywgbWVkaW9zIHkgYmFqb3MuIA0KDQoqIFBhcmEgZWxsbywgcHJpbWVybyBzZSBnZW5lcmEgdW5hIG51ZXZhIHZhcmlhYmxlIGRlIHByZWNpb3MgcG9yIG1ldHJvIGN1YWRyYWRvIGBweG0yYCBwYXJhIHBvZGVyIGdlbmVyYXIgdW5hIGNsYXNpZmljYWNpw7NuIGRlbCBiYXJyaW8gZW4gYmFzZSBhIHVuYSBkZWNpc2nDs24gZGUgbmVnb2NpbyAobG8gcXVlIHZhbGUgZW4gcHJvbWVkaW8gZWwgbWV0cm8gY3VhZHJhZG8gZW4gY2FkYSBiYXJyaW8pLiANCg0KYGBge3J9DQojIENyZWFtb3MgdW5hIG51ZXZhIHZhcmlhYmxlICBkZSBwcmVjaW9zIHBvciBtZXRybyBjdWFkcmFkbw0KdHJhaW5fZGF0YSA9IHRyYWluX2RhdGEgJT4lIA0KICBtdXRhdGUocHhtMiA9IHJvdW5kKHByaWNlL3N1cmZhY2VfdG90YWwsMCkpDQojIEFybWFtb3MgdW4gZGF0YWZyYW1lIHF1ZSBtdWVzdHJlIGxvcyBwcm9tZWRpb3MgZGUgcHhtMiBlbiBjYWRhIGJhcnJpbw0KQVZHX3B4bTJfbDMgPSB0cmFpbl9kYXRhICU+JSANCiAgZ3JvdXBfYnkobDMpICU+JQ0KICBzdW1tYXJpc2UoQVZHX3B4bTJfbDMgPSBtZWFuKHB4bTIpKQ0KQVZHX3B4bTJfbDMNCmBgYA0KDQpPYnNlcnZlbW9zIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIHByZWNpb3MgcHJvbWVkaW8gcG9yIG0yLiANCg0KYGBge3J9DQojIGJveHBsb3QgZGUgcHJlY2lvcyBwb3IgbWV0cm8gY3VhZHJhZG8NCmdncGxvdChkYXRhID0gQVZHX3B4bTJfbDMsIGFlcyh4ID0gQVZHX3B4bTJfbDMpKSArIA0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjc1KSArDQogIGxhYnModGl0bGUgPSAiQm94cGxvdCBkZSBwcmVjaW9zIHByb21lZGlvIGRlIGJhcnJpb3MgcG9yIG0yIikgKw0KICBsYWJzKHggPSAiUHJlY2lvcyBwcm9tZWRpbyBkZSBiYXJyaW9zIHBvciBtMiIpDQpgYGANCkFwbGljYXJlbW9zIGVsIHNpZ3VpZW50ZSBjcml0ZXJpbyBwYXJhIGFncnVwYXIgbG9zIGJhcnJpb3MgZW46DQoNCiogKipwcmVjaW9fYmFqbyoqOiAgYmFycmlvcyBjdXlvIHByZWNpbyBwcm9tZWRpbyBwb3IgbTIgc2VhIG1lbm9yIGFsIFExDQoqICoqcHJlY2lvX21lZGlvKio6IGJhcnJpb3MgY3V5byBwcmVjaW8gcHJvbWVkaW8gc2UgZW5jdWVudHJlIGVuIGVsIFJJDQoqICoqcHJlY2lvX2FsdG8qKjogYmFycmlvcyBjdXlvIHByZWNpbyBwcm9tZWRpbyBwb3IgbTIgc2VhIG1heW9yIGFsIFEzDQoNCmBgYHtyfQ0KIyBhcm1hbW9zIG51ZXZhIHZhcmlhYmxlIHNpZ3VpZW5kbyB0YWxlcyBjcml0ZXJpb3MNCkFWR19weG0yX2wzID0gQVZHX3B4bTJfbDMgJT4lDQogIG11dGF0ZSh0aXBvX2JhcnJpbyA9IGNhc2Vfd2hlbigNCiAgICBBVkdfcHhtMl9sMyA8IHF1YW50aWxlKEFWR19weG0yX2wzKVsyXSB+ICJwcmVjaW9fYmFqbyIsDQogICAgQVZHX3B4bTJfbDMgPj0gcXVhbnRpbGUoQVZHX3B4bTJfbDMpWzJdICYgQVZHX3B4bTJfbDMgPCBxdWFudGlsZShBVkdfcHhtMl9sMylbNF0gfiAicHJlY2lvX21lZGlvIiwNCiAgICBUUlVFIH4gInByZWNpb19hbHRvIg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KICAgICAgICAgKQ0Kd3JpdGUuY3N2KEFWR19weG0yX2wzLCAnQVZHX3B4bTJfbDMuY3N2JykNCiMgd3JpdGVfY3N2KEFWR19weG0yX2wzLCAnQVZHX3B4bTJfbDNfLmNzdicpDQojIHVuaW1vcyBlc3RhIGNsYXNpZmljYWNpw7NuIGFsIGRhdGFzZXQgb3JpZ2luYWwNCnRyYWluX2RhdGEgPSB0cmFpbl9kYXRhICU+JSBsZWZ0X2pvaW4oQVZHX3B4bTJfbDMsIGJ5ID0gJ2wzJykgDQpoZWFkKHRyYWluX2RhdGEpDQpgYGANCg0KQWp1c3RhbW9zIGVsIG1vZGVsbyBjb24gbGEgbnVldmEgdmFyaWFibGUgdGlwb19iYXJyaW8gZW4gdmV6IGRlIGwzLiANCg0KYGBge3J9DQojIGFqdXN0YW1vcyBlbCBtb2RlbG8NCm1vZGVsb19zY190YiA8LSBsbShwcmljZSB+IHN1cmZhY2VfY292ZXJlZCArIHRpcG9fYmFycmlvLCBkYXRhID0gdHJhaW5fZGF0YSkNCnRpZHlfc2NfdGIgPC0gdGlkeShtb2RlbG9fc2NfdGIsIGNvbmYuaW50ID0gVFJVRSkNCnRpZHlfc2NfdGINCmBgYA0KDQrCv1F1w6kgcGFzYSBhaG9yYSBjb24gbGEgc2lnbmlmaWNhdGl2aWRhZCBkZSBsb3MgcHJlZGljdG9yZXM/